java 生成 0 到 1000 之间的唯一随机数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10692978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 02:08:11  来源:igfitidea点击:

Generate unique random number between 0 and 1000

javarandom

提问by AKIWEB

Possible Duplicate:
Generating Unique Random Numbers in Java

可能的重复:
在 Java 中生成唯一的随机数

How can I generate random number between 0 and 1000 and keep on passing unique random number that got generated between 0 and 1000 to a particular method. So for that I generated the number between 0 and 1000 and inserted unique random number between 0 and 1000 in List so that we can compare whether the random number we are generating is already present in the list or not. If it is present then generate it again. But somehow I believe the below code will fail sometimes.

如何生成 0 到 1000 之间的随机数并继续将在 0 到 1000 之间生成的唯一随机数传递给特定方法。为此,我生成了 0 到 1000 之间的数字,并在 List 中插入了 0 到 1000 之间的唯一随机数,以便我们可以比较我们生成的随机数是否已经存在于列表中。如果它存在,则再次生成它。但不知何故,我相信下面的代码有时会失败。

public class Testing4 {
    private static List<Integer> randomNumber;
    private static Random r = new Random();
    private static int rand;
    private static int endRange = 1000;

    public static void main(String args[]) throws IOException {

        randomNumber = new ArrayList<Integer>();

        for (int i = 1; i<= endRange; i++) {
            rand = r.nextInt(endRange);

            if(randomNumber.contains(rand)) {
                rand = r.nextInt(endRange);
            } else {
                randomNumber.add(rand);
            }

        // Pass the unique random number between 0 and 1000 to this method      
                randomNumberMethod(rand);

        }
    }
}

回答by Malcolm Smith

You are essentially generating a List of the numbers from 0-1000 in a random order. You could achieve this more efficiently in the following way:

您实际上是按随机顺序生成 0-1000 之间的数字列表。您可以通过以下方式更有效地实现这一目标:

public class Testing4 {
    private static List<Integer> randomNumber;
    private static int endRange = 1000;

    public static void main(String args[]) throws IOException {

        randomNumber = new ArrayList<Integer>(endRange);

        for (int i = 0; i<= endRange; i++) {                
            randomNumber.add(i);
        }

        Collections.shuffle(randomNumber);

        for (int i = 0; i<= endRange; i++) {                
            // Pass the unique random number between 0 and 1000 to this method      
            randomNumberMethod(randomNumber.get(i));
        }
    }
}

Think about what will be happening by the time you get to 999 - you will have a 1 in 999 chance of 'guessing' the remaining available number each time round the loop.

想想当你达到 999 时会发生什么——你将有 999 分之一的机会“猜测”剩余的可用数字,每次循环。

回答by Neil Coffey

To generate a unique list of numbers between 0 and 1000, do the following:

要生成 0 到 1000 之间的唯一数字列表,请执行以下操作:

  • create a list containing all the numbers from 0 to 1000
  • shuffle the list using Collections.shuffle()
  • take the first however many numbers you need from the list.
  • 创建一个包含从 0 到 1000 的所有数字的列表
  • 使用 Collections.shuffle() 打乱列表
  • 从列表中取出您需要的第一个数字。

There are cases where a more complex algorithm is called for, but if the range of possible numbers and count of items you need to select are both in the order of 1000 you really may as well just take the first nnumbers from a randomly shuffled list of all the possibilities.

在某些情况下需要更复杂的算法,但是如果您需要选择的可能数字的范围和项目数都在 1000 的数量级,那么您真的可以从随机排列的列表中取出前n 个数字所有的可能性。

If you do want to do something like you suggest, then:

如果你确实想做一些你建议的事情,那么:

  • use a while loop as another poster has suggested
  • use a Set, not a list, to store the already-chosen values.
  • 正如另一张海报所建议的那样使用 while 循环
  • 使用 Set 而不是列表来存储已经选择的值。

However, this becomes inefficient as the number of items to select tends in magnitude towards the number of possible items (so e.g. if you're selecting 10 numbers out of a possible 1000, then it'll be OK; it you're selecting 900 out of a possible 1000 it will become inefficient as more and more numbers need to be rejected each time before finding one not previously chosen).

然而,这会变得低效,因为要选择的项目数量在数量上趋向于可能项目的数量(例如,如果您从可能的 1000 个数字中选择 10 个数字,那么就可以了;如果您选择的是 900在可能的 1000 个中,它会变得低效,因为每次都需要拒绝越来越多的数字,然后才能找到以前未选择的数字)。

回答by Konstantin Tarashchanskiy

From code inspection, I cannot see anything in this method that will stop it from WORKING, it is just very inefficient.

从代码检查中,我看不到这种方法中的任何内容会阻止它工作,它只是非常低效。

For one thing, checking to see if the number is one that you have seen randomNumber.contains(rand)will take more and more time the more numbers you generate since each time you do it, you will have to compare it against every number in the list until either you find one that matches or you have tried every number in the list. A better way to do this is to use a HashSetinstead of a list which should make every membership test take the same amount of time regardless of how many things you have put in it.

一方面,检查数字是否是您见过的数字randomNumber.contains(rand)将花费越来越多的时间,因为您生成的数字越多,因为每次这样做时,您都必须将其与列表中的每个数字进行比较,直到您找到匹配或您已尝试列表中的每个数字。一个更好的方法是使用一个HashSet列表而不是一个列表,它应该使每个成员资格测试花费相同的时间,而不管你放入了多少东西。

A second, and more significant optimization can be done by noting that you may be asking the wrong question. Are you trying to generate unique, random numbers or are you trying to generate every number between 1 and endRange in random order? If you are going to want every number (or even a non-trivial portion of them), it is going to be a great deal faster to just put every number from 1 to 1000 into a list and then shuffle them using Collections.shuffle. So your generation code is going to be:

通过注意您可能问错了问题,可以完成第二个更重要的优化。您是要生成唯一的随机数,还是要以随机顺序生成 1 和 endRange 之间的每个数字?如果您想要每个数字(甚至它们的重要部分),只需将 1 到 1000 之间的每个数字放入一个列表中,然后使用Collections.shuffle. 所以你的生成代码将是:

java.util.List<Integer> nums = new java.util.ArrayList<Integer>(1001);
for (int i = 0; i <= 1000; i++)
{
   nums.add(new Integer(i));
}
java.util.Collections.shuffle(nums);

回答by Dima

Your code will fail if 2 numbers that already exist in your ArrayList are generated consecutively. It will use the second number whether it is a duplicate or not. The if statement should be a while loop instead (to keep trying until it generates a unique one).

如果连续生成 ArrayList 中已经存在的 2 个数字,则您的代码将失败。无论是否重复,它将使用第二个数字。if 语句应该是一个 while 循环(继续尝试直到它生成一个唯一的循环)。

public class Testing4 {
    private static HashSet<Integer> randomNumber;
    private static Random r = new Random();
    private static int rand;
    private static int endRange = 1000;

    public static void main(String args[]) throws IOException {

        randomNumber = new HashSet<Integer>();

        for (int i = 1; i<= endRange; i++) {    
            do
            {
               rand = r.nextInt(endRange);
            }
            while(randomNumber.contains(rand));

            randomNumber.add(rand);

            // Pass the unique random number between 0 and 1000 to this method      
            randomNumberMethod(rand);

        }
    }
}

edit: as per the comments, you should use a do/while and a hashing data structure rather than an arraylist to speed up the duplicate lookups. The final edits are in the code above.

编辑:根据评论,您应该使用 do/while 和散列数据结构而不是数组列表来加速重复查找。最终编辑在上面的代码中。