简体   繁体   English

在 Java 中生成唯一的随机数

[英]Generating Unique Random Numbers in Java

I'm trying to get random numbers between 0 and 100. But I want them to be unique, not repeated in a sequence.我试图获得 0 到 100 之间的随机数。但我希望它们是唯一的,而不是按顺序重复。 For example if I got 5 numbers, they should be 82,12,53,64,32 and not 82,12,53,12,32 I used this, but it generates same numbers in a sequence.例如,如果我有 5 个数字,它们应该是 82,12,53,64,32 而不是 82,12,53,12,32 我使用了这个,但它会在一个序列中生成相同的数字。

Random rand = new Random();
selected = rand.nextInt(100);
  • Add each number in the range sequentially in a list structure.将范围内的每个数字按顺序添加到列表结构中。
  • Shuffle it. 随机播放
  • Take the first 'n'.取第一个'n'。

Here is a simple implementation.这是一个简单的实现。 This will print 3 unique random numbers from the range 1-10.这将打印 1-10 范围内的 3 个唯一随机数。

import java.util.ArrayList;
import java.util.Collections;

public class UniqueRandomNumbers {
    
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        for (int i=1; i<11; i++) list.add(i);
        Collections.shuffle(list);
        for (int i=0; i<3; i++) System.out.println(list.get(i));
    }
}

The first part of the fix with the original approach, as Mark Byers pointed out in an answer now deleted, is to use only a single Random instance.正如 Mark Byers 在现已删除的答案中指出的那样,使用原始方法修复的第一部分是仅使用单个Random实例。

That is what is causing the numbers to be identical.这就是导致数字相同的原因。 A Random instance is seeded by the current time in milliseconds.一个Random实例由当前时间播种,以毫秒为单位。 For a particular seed value, the 'random' instance will return the exact same sequence of pseudo random numbers.对于特定的种子值, “随机”实例将返回完全相同伪随机数序列。

With Java 8+ you can use the ints method of Random to get an IntStream of random values then distinct and limit to reduce the stream to a number of unique random values.使用 Java 8+,您可以使用Randomints方法获取随机值的IntStream ,然后distinctlimit以将流减少为多个唯一随机值。

ThreadLocalRandom.current().ints(0, 100).distinct().limit(5).forEach(System.out::println);

Random also has methods which create LongStream s and DoubleStream s if you need those instead. Random也有创建LongStreamDoubleStream的方法,如果你需要的话。

If you want all (or a large amount) of the numbers in a range in a random order it might be more efficient to add all of the numbers to a list, shuffle it, and take the first n because the above example is currently implemented by generating random numbers in the range requested and passing them through a set (similarly to Rob Kielty's answer ), which may require generating many more than the amount passed to limit because the probability of a generating a new unique number decreases with each one found.如果您希望某个范围内的所有(或大量)数字以随机顺序排列,则将所有数字添加到列表中,打乱它并取第一个 n 可能会更有效,因为上面的示例当前已实现通过在请求的范围内生成随机数并将它们传递给一组(类似于Rob Kielty 的答案),这可能需要生成比传递给限制的数量多得多的数量,因为生成一个新的唯一数字的概率随着找到一个而降低。 Here's an example of the other way:这是另一种方式的示例:

List<Integer> range = IntStream.range(0, 100).boxed()
        .collect(Collectors.toCollection(ArrayList::new));
Collections.shuffle(range);
range.subList(0, 99).forEach(System.out::println);
  1. Create an array of 100 numbers, then randomize their order.创建一个包含 100 个数字的数组,然后随机排列它们的顺序。
  2. Devise a pseudo-random number generator that has a range of 100.设计一个范围为 100 的伪随机数生成器。
  3. Create a boolean array of 100 elements, then set an element true when you pick that number.创建一个包含 100 个元素的布尔数组,然后在选择该数字时将一个元素设置为 true。 When you pick the next number check against the array and try again if the array element is set.当您选择下一个数字时,请检查数组并重试是否设置了数组元素。 (You can make an easy-to-clear boolean array with an array of long where you shift and mask to access individual bits.) (您可以制作一个易于清除的布尔数组,其中包含一个long数组,您可以在其中移位和屏蔽以访问各个位。)

对所有 100 个数字使用Collections.shuffle()并选择前五个,如此处所示

I feel like this method is worth mentioning.我觉得这个方法值得一提。

   private static final Random RANDOM = new Random();    
   /**
     * Pick n numbers between 0 (inclusive) and k (inclusive)
     * While there are very deterministic ways to do this,
     * for large k and small n, this could be easier than creating
     * an large array and sorting, i.e. k = 10,000
     */
    public Set<Integer> pickRandom(int n, int k) {
        final Set<Integer> picked = new HashSet<>();
        while (picked.size() < n) {
            picked.add(RANDOM.nextInt(k + 1));
        }
        return picked;
    }

I re-factored Anand's answer to make use not only of the unique properties of a Set but also use the boolean false returned by the set.add() when an add to the set fails.我重构了 Anand 的答案,不仅利用了 Set 的独特属性,还使用了set.add()在添加到集合失败时返回的布尔值 false。

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class randomUniqueNumberGenerator {

    public static final int SET_SIZE_REQUIRED = 10;
    public static final int NUMBER_RANGE = 100;

    public static void main(String[] args) {
        Random random = new Random();

        Set set = new HashSet<Integer>(SET_SIZE_REQUIRED);

        while(set.size()< SET_SIZE_REQUIRED) {
            while (set.add(random.nextInt(NUMBER_RANGE)) != true)
                ;
        }
        assert set.size() == SET_SIZE_REQUIRED;
        System.out.println(set);
    }
}

I have made this like that.我做了这个。

    Random random = new Random();
    ArrayList<Integer> arrayList = new ArrayList<Integer>();

    while (arrayList.size() < 6) { // how many numbers u need - it will 6
        int a = random.nextInt(49)+1; // this will give numbers between 1 and 50.

        if (!arrayList.contains(a)) {
            arrayList.add(a);
        }
    }

This will work to generate unique random numbers................这将用于生成唯一的随机数......

import java.util.HashSet;
import java.util.Random;

public class RandomExample {

    public static void main(String[] args) {
        Random rand = new Random();
        int e;
        int i;
        int g = 10;
        HashSet<Integer> randomNumbers = new HashSet<Integer>();

        for (i = 0; i < g; i++) {
            e = rand.nextInt(20);
            randomNumbers.add(e);
            if (randomNumbers.size() <= 10) {
                if (randomNumbers.size() == 10) {
                    g = 10;
                }
                g++;
                randomNumbers.add(e);
            }
        }
        System.out.println("Ten Unique random numbers from 1 to 20 are  : " + randomNumbers);
    }
}

One clever way to do this is to use exponents of a primitive element in modulus.一种聪明的方法是在模数中使用原始元素的指数。

For example, 2 is a primitive root mod 101, meaning that the powers of 2 mod 101 give you a non-repeating sequence that sees every number from 1 to 100 inclusive:例如,2 是原始根 mod 101,这意味着 2 mod 101 的幂为您提供了一个不重复的序列,可以看到从 1 到 100 的每个数字:

2^0 mod 101 = 1
2^1 mod 101 = 2
2^2 mod 101 = 4
...
2^50 mod 101 = 100
2^51 mod 101 = 99
2^52 mod 101 = 97
...
2^100 mod 101 = 1

In Java code, you would write:在 Java 代码中,您将编写:

void randInts() {
int num=1;
for (int ii=0; ii<101; ii++) {
    System.out.println(num);
    num= (num*2) % 101;
    }
}

Finding a primitive root for a specific modulus can be tricky, but Maple's "primroot" function will do this for you.找到特定模数的原始根可能很棘手,但 Maple 的“primroot”函数将为您完成此任务。

I have come here from another question, which has been duplicate of this question ( Generating unique random number in java )我是从另一个问题来到这里的,该问题与这个问题重复( 在 java 中生成唯一随机数

  1. Store 1 to 100 numbers in an Array.在一个数组中存储 1 到 100 个数字。

  2. Generate random number between 1 to 100 as position and return array[position-1] to get the value生成 1 到 100 之间的随机数作为位置并返回 array[position-1] 以获取值

  3. Once you use a number in array, mark the value as -1 ( No need to maintain another array to check if this number is already used)在数组中使用数字后,将值标记为 -1(无需维护另一个数组来检查该数字是否已被使用)

  4. If value in array is -1, get the random number again to fetch new location in array.如果数组中的值为-1,则再次获取随机数以获取数组中的新位置。

I have easy solution for this problem, With this we can easily generate n number of unique random numbers, Its just logic anyone can use it in any language.对于这个问题我有一个简单的解决方案,有了这个我们可以很容易地生成 n 个唯一的随机数,这只是任何人都可以用任何语言使用它的逻辑。

for(int i=0;i<4;i++)
        {
            rn[i]= GenerateRandomNumber();
            for (int j=0;j<i;j++)
            {
                if (rn[i] == rn[j])
                {
                    i--;
                }
            }
        }

Though it's an old thread, but adding another option might not harm.虽然这是一个旧线程,但添加另一个选项可能不会有害。 (JDK 1.8 lambda functions seem to make it easy); (JDK 1.8 lambda 函数似乎让它变得简单);

The problem could be broken down into the following steps;问题可以分解为以下步骤;

  • Get a minimum value for the provided list of integers (for which to generate unique random numbers)获取提供的整数列表的最小值(为其生成唯一的随机数)
  • Get a maximum value for the provided list of integers获取提供的整数列表的最大值
  • Use ThreadLocalRandom class (from JDK 1.8) to generate random integer values against the previously found min and max integer values and then filter to ensure that the values are indeed contained by the originally provided list.使用 ThreadLocalRandom 类(来自 JDK 1.8)针对先前找到的最小和最大整数值生成随机整数值,然后过滤以确保这些值确实包含在最初提供的列表中。 Finally apply distinct to the intstream to ensure that generated numbers are unique.最后对 intstream 应用 distinct 以确保生成的数字是唯一的。

Here is the function with some description:这是带有一些描述的功能:

/**
 * Provided an unsequenced / sequenced list of integers, the function returns unique random IDs as defined by the parameter
 * @param numberToGenerate
 * @param idList
 * @return List of unique random integer values from the provided list
 */
private List<Integer> getUniqueRandomInts(List<Integer> idList, Integer numberToGenerate) {

    List<Integer> generatedUniqueIds = new ArrayList<>();

    Integer minId = idList.stream().mapToInt (v->v).min().orElseThrow(NoSuchElementException::new);
    Integer maxId = idList.stream().mapToInt (v->v).max().orElseThrow(NoSuchElementException::new);

            ThreadLocalRandom.current().ints(minId,maxId)
            .filter(e->idList.contains(e))
            .distinct()
            .limit(numberToGenerate)
            .forEach(generatedUniqueIds:: add);

    return generatedUniqueIds;

}

So that, to get 11 unique random numbers for 'allIntegers' list object, we'll call the function like;因此,要为 'allIntegers' 列表对象获取 11 个唯一随机数,我们将调用该函数:

    List<Integer> ids = getUniqueRandomInts(allIntegers,11);

The function declares new arrayList 'generatedUniqueIds' and populates with each unique random integer up to the required number before returning.该函数声明了新的 arrayList 'generatedUniqueIds' 并在返回之前使用每个唯一的随机整数填充到所需的数字。

PS ThreadLocalRandom class avoids common seed value in case of concurrent threads. PS ThreadLocalRandom 类在并发线程的情况下避免公共种子值。

Following code will generate 5 random numbers between 1 to 100以下代码将生成 1 到 100 之间的 5 个随机数

 public static void main(String[] args) {
        Random random = new Random();
        HashSet<Integer> set = new HashSet<>();
        while (set.size() < 5) {
            int a = random.nextInt(99)+1;
            if (!set.contains(a)) {
                set.add(a);
            }
        }
        System.out.println(set);
    }

try this out试试这个

public class RandomValueGenerator {
    /**
     * 
     */
    private volatile List<Double> previousGenValues = new ArrayList<Double>();

    public void init() {
        previousGenValues.add(Double.valueOf(0));
    }

    public String getNextValue() {
        Random random = new Random();
        double nextValue=0;
        while(previousGenValues.contains(Double.valueOf(nextValue))) {
            nextValue = random.nextDouble();
        }
        previousGenValues.add(Double.valueOf(nextValue));
        return String.valueOf(nextValue);
    }
}

Choose n unique random numbers from 0 to m-1.从 0 到 m-1 中选择 n 个唯一的随机数。

int[] uniqueRand(int n, int m){
    Random rand = new Random();
    int[] r = new int[n];
    int[] result = new int[n];
    for(int i = 0; i < n; i++){
        r[i] = rand.nextInt(m-i);
        result[i] = r[i];
        for(int j = i-1; j >= 0; j--){
            if(result[i] >= r[j])
                result[i]++;
        }
    }
    return result;
}

Imagine a list containing numbers from 0 to m-1.想象一个包含从 0 到 m-1 的数字的列表。 To choose the first number, we simply use rand.nextInt(m) .要选择第一个数字,我们只需使用rand.nextInt(m) Then remove the number from the list.然后从列表中删除该号码。 Now there remains m-1 numbers, so we call rand.nextInt(m-1) .现在还有 m-1 个数字,所以我们调用rand.nextInt(m-1) The number we get represents the position in the list.我们得到的数字代表列表中的位置。 If it is less than the first number, then it is the second number, since the part of list prior to the first number wasn't changed by the removal of the first number.如果它小于第一个数字,则它是第二个数字,因为在第一个数字之前的列表部分没有因删除第一个数字而改变。 If the position is greater than or equal to the first number, the second number is position+1.如果位置大于或等于第一个数字,则第二个数字是位置+1。 Do some further derivation, you can get this algorithm.进一步推导,就可以得到这个算法。

Explanation解释

This algorithm has O(n^2) complexity.该算法具有 O(n^2) 复杂度。 So it is good for generating small amount of unique numbers from a large set.因此,它适用于从大量集合中生成少量唯一数字。 While the shuffle based algorithm need at least O(m) to do the shuffle.而基于 shuffle 的算法至少需要 O(m) 来进行 shuffle。

Also shuffle based algorithm need memory to store every possible outcome to do the shuffle, this algorithm doesn't need.此外,基于洗牌的算法需要内存来存储每一个可能的结果来进行洗牌,这个算法不需要。

This isn't significantly different from other answers, but I wanted the array of integers in the end:这与其他答案没有显着不同,但我最后想要整数数组:

    Integer[] indices = new Integer[n];
    Arrays.setAll(indices, i -> i);
    Collections.shuffle(Arrays.asList(indices));
    return Arrays.stream(indices).mapToInt(Integer::intValue).toArray();

you can use boolean array to fill the true if value taken else set navigate through boolean array to get value as per given below您可以使用布尔数组填充 true if 取值否则设置导航通过布尔数组以获取值,如下所示

package study;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/*
Created By Sachin  Rane on Jul 18, 2018
*/
public class UniqueRandomNumber {
    static Boolean[] boolArray;
    public static void main(String s[]){
        List<Integer> integers = new ArrayList<>();


        for (int i = 0; i < 10; i++) {
            integers.add(i);
        }


        //get unique random numbers
        boolArray = new Boolean[integers.size()+1];
        Arrays.fill(boolArray, false);
        for (int i = 0; i < 10; i++) {
            System.out.print(getUniqueRandomNumber(integers) + " ");

        }

    }

    private static int  getUniqueRandomNumber(List<Integer> integers) {
        int randNum =(int) (Math.random()*integers.size());
        if(boolArray[randNum]){
            while(boolArray[randNum]){
                randNum++;
                if(randNum>boolArray.length){
                    randNum=0;
                }
            }
            boolArray[randNum]=true;
            return randNum;
        }else {
            boolArray[randNum]=true;
            return randNum;
        }

    }

}

This is the most simple method to generate unique random values in a range or from an array .这是在范围内或从数组中生成唯一随机值的最简单方法

In this example, I will be using a predefined array but you can adapt this method to generate random numbers as well.在此示例中,我将使用预定义的数组,但您也可以调整此方法以生成随机数。 First, we will create a sample array to retrieve our data from.首先,我们将创建一个示例数组来从中检索数据。

  1. Generate a random number and add it to the new array.生成一个随机数并将其添加到新数组中。
  2. Generate another random number and check if it is already stored in the new array.生成另一个随机数并检查它是否已存储在新数组中。
  3. If not then add it and continue如果没有,则添加并继续
  4. else reiterate the step.否则重复该步骤。
ArrayList<Integer> sampleList = new ArrayList<>();
sampleList.add(1);
sampleList.add(2);
sampleList.add(3);
sampleList.add(4);
sampleList.add(5);
sampleList.add(6);
sampleList.add(7);
sampleList.add(8);

Now from the sampleList we will produce five random numbers that are unique.现在从sampleList我们将产生五个唯一的随机数。

int n;
randomList = new ArrayList<>();
for(int  i=0;i<5;i++){
    Random random = new Random();
    n=random.nextInt(8);     //Generate a random index between 0-7

    if(!randomList.contains(sampleList.get(n)))
    randomList.add(sampleList.get(n));
    else
        i--;    //reiterating the step
}
        

This is conceptually very simple.这在概念上非常简单。 If the random value generated already exists then we will reiterate the step.如果生成的随机值已经存在,那么我们将重复该步骤。 This will continue until all the values generated are unique.这将一直持续到生成的所有值都是唯一的。

If you found this answer useful then you can vote it up as it is much simple in concept as compared to the other answers .如果您发现此答案有用,则可以投票,因为与其他答案相比,它在概念上要简单得多

Check this检查这个

public class RandomNumbers {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int n = 5;
        int A[] = uniqueRandomArray(n);
        for(int i = 0; i<n; i++){
            System.out.println(A[i]);
        }
    }
    public static int[] uniqueRandomArray(int n){
        int [] A = new int[n];
        for(int i = 0; i< A.length; ){
            if(i == A.length){
                break;
            }
            int b = (int)(Math.random() *n) + 1;
            if(f(A,b) == false){
                A[i++] = b;
            } 
        }
        return A;
    }
    public static boolean f(int[] A, int n){
        for(int i=0; i<A.length; i++){
            if(A[i] == n){
                return true;
            }
        }
        return false;
    }
}

Below is a way I used to generate unique number always.以下是我用来始终生成唯一编号的一种方式。 Random function generates number and stores it in textfile then next time it checks it in file compares it and generate new unique number hence in this way there is always a new unique number.随机函数生成数字并将其存储在文本文件中,然后下次在文件中检查它时比较它并生成新的唯一数字,因此这样总是有一个新的唯一数字。

public int GenerateRandomNo()
{
    int _min = 0000;
    int _max = 9999;
    Random _rdm = new Random();
    return _rdm.Next(_min, _max);
}
public int rand_num()
{
    randnum = GenerateRandomNo();
    string createText = randnum.ToString() + Environment.NewLine;
    string file_path = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + @"\Invoices\numbers.txt";
    File.AppendAllText(file_path, createText);
    int number = File.ReadLines(file_path).Count(); //count number of lines in file
    System.IO.StreamReader file = new System.IO.StreamReader(file_path);
    do
    {
        randnum = GenerateRandomNo();
    }
    while ((file.ReadLine()) == randnum.ToString());
    file.Close();
    return randnum;

}

You can use the Collections class.您可以使用 Collections 类。

A utility class called Collections offers different actions that can be performed on a collection like an ArrayList (eg, search the elements, find the maximum or minimum element, reverse the order of elements, and so on).一个名为 Collections 的实用程序类提供了可以在像 ArrayList 这样的集合上执行的不同操作(例如,搜索元素、查找最大或最小元素、反转元素的顺序等)。 One of the actions it can perform is to shuffle the elements.它可以执行的操作之一是随机播放元素。 The shuffle will randomly move each element to a different position in the list.随机播放会将每个元素随机移动到列表中的不同位置。 It does this by using a Random object.它通过使用 Random 对象来做到这一点。 This means it's deterministic randomness, but it will do in most situations.这意味着它是确定性随机性,但在大多数情况下都可以。

To shuffle the ArrayList, add the Collections import to the top of the program and then use the Shuffle static method.要随机播放 ArrayList,请将 Collections 导入添加到程序顶部,然后使用 Shuffle 静态方法。 It takes the ArrayList to be shuffled as a parameter:它将 ArrayList 作为参数进行混洗:

import java.util.Collections;
import java.util.ArrayList;
public class Lottery {
public static void main(String[] args) {
//define ArrayList to hold Integer objects
ArrayList numbers = new ArrayList();
for(int i = 0; i < 100; i++)
{
numbers.add(i+1);
}
Collections.shuffle(numbers);
System.out.println(numbers);
}
}

You can generate n unique random number between 0 to n-1 in java您可以在java中生成0到n-1之间的n个唯一随机数

public static void RandomGenerate(int n)
{
     Set<Integer> st=new HashSet<Integer>();
     Random r=new Random();
     while(st.size()<n)
     {
        st.add(r.nextInt(n));
     }

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM