35

I want to create a set of random numbers without duplicates in Java.

For example I have an array to store 10,000 random integers from 0 to 9999.

Here is what I have so far:

import java.util.Random;
public class Sort{

    public static void main(String[] args){

        int[] nums = new int[10000];

        Random randomGenerator = new Random();

        for (int i = 0; i < nums.length; ++i){
            nums[i] = randomGenerator.nextInt(10000);
        }
    }
}

But the above code creates duplicates. How can I make sure the random numbers do not repeat?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Fernando Martinez
  • 549
  • 1
  • 5
  • 10
  • 1
    possible duplicate of [Generate unique random numbers in Java](http://stackoverflow.com/questions/9423523/generate-unique-random-numbers-in-java) – JB Nizet Apr 14 '13 at 14:35
  • 2
    But if you remove repeated numbers, then they're not as random – 000 Apr 14 '13 at 14:37
  • 1
    Do you want *all* 10.000 numbers in the array in a random order, or do you want 10.000 random numbers? because you can't have 10.000 random numbers within the range of 0 - 9.999 (then they are not random anymore) – GameDroids Apr 14 '13 at 14:40
  • Yeah I just do not want them to repeat that is the most important thing. – Fernando Martinez Apr 14 '13 at 14:51
  • Do you want it not to repeat in the way of "1 1 2" repeats? Is "1 2 1" an acceptable sequence? –  Apr 14 '13 at 15:50
  • Hmm I am not exactly sure this is a homework assigment and my teacher said no repeats in the assignment so I guess 121would be acceptable – Fernando Martinez Apr 14 '13 at 16:03
  • I will delete this question because it is a duplicate. – Fernando Martinez Apr 14 '13 at 16:16
  • @FernandoMartinez Why you want to delete this question? You should select best answer and accept instead. Duplicate doesn't mean you have to delete question. – Achintya Jha Apr 14 '13 at 16:46
  • For homework, please consider talking to your instructor. Some of the concepts below (lazy evaluation) may be beyond what you are supposed to be learning (not a bad thing, but teaching is about bringing students to an end point along a prescribed path - if they deviate from the path, they may not get to the endpoint). Handing in an assignment that uses these concepts that you don't understand is worse than handing in one that doesn't work because you didn't learn this step and may have more difficulty with the next. –  Apr 14 '13 at 16:58
  • @AchintyaJha it can't be deleted - there is a positively scored answer to it. –  Apr 14 '13 at 16:59
  • possible duplicate of [Generating Unique Random Numbers in Java](http://stackoverflow.com/questions/8115722/generating-unique-random-numbers-in-java) – Greg Hewgill Apr 14 '13 at 21:45
  • 105 k view I am very proud of this accomplishment – Fernando Martinez Mar 09 '21 at 02:48

12 Answers12

49
Integer[] arr = {...};
Collections.shuffle(Arrays.asList(arr));

For example:

public static void main(String[] args) {
    Integer[] arr = new Integer[1000];
    for (int i = 0; i < arr.length; i++) {
        arr[i] = i;
    }
    Collections.shuffle(Arrays.asList(arr));
    System.out.println(Arrays.toString(arr));

}
Achintya Jha
  • 12,735
  • 2
  • 27
  • 39
  • 1
    Shuffle is great but first you should create array that contains numbers from 0 to 9999 and then shuffle it. Also, what is the time complexity of shuffle? – Martinsos Apr 14 '13 at 14:37
  • 1
    @Martinsos I created array and shuffled it. I am not sure but I think time complexity of shuffle should be O(n). Because if just do swapping randomly inside an array. – Achintya Jha Apr 14 '13 at 15:09
10

A simple algorithm that gives you random numbers without duplicates can be found in the book Programming Pearls p. 127.

Attention: The resulting array contains the numbers in order! If you want them in random order, you have to shuffle the array, either with Fisher–Yates shuffle or by using a List and call Collections.shuffle().

The benefit of this algorithm is that you do not need to create an array with all the possible numbers and the runtime complexity is still linear O(n).

public static int[] sampleRandomNumbersWithoutRepetition(int start, int end, int count) {
    Random rng = new Random();

    int[] result = new int[count];
    int cur = 0;
    int remaining = end - start;
    for (int i = start; i < end && count > 0; i++) {
        double probability = rng.nextDouble();
        if (probability < ((double) count) / (double) remaining) {
            count--;
            result[cur++] = i;
        }
        remaining--;
    }
    return result;
}
the
  • 361
  • 3
  • 9
  • 1
    Note: (re: your "Attention" section) `Collections.shuffle` is doing a Fisher-Yates shuffle, so it's not an "either-or" situation. – Erwin Bolwidt Dec 06 '17 at 04:01
  • You are right, `Collections.shuffle` does a Fisher-Yates shuffle, but you need a `List` to use it. `Arrays.asList` needs the array to be of type `Integer` instead of `int` to do the conversion correctly, then you do not have to allocate additional memory. Writing the Fisher-Yates shuffle yourself avoids the conversion and no additional memory is needed. – the Dec 07 '17 at 11:34
  • just trying to understand why `probability < ((double) count) / (double) remaining` is needed? why not fill the array from start to end and just shuffle? – brain storm Jul 20 '18 at 03:26
  • This answer does not get the credit it deserves. Been doing some histograms on the results to check for randomnes, and so far the results are as evenly spread as expected. For example, there is no noticeable differences between `sampleRandomNumbersWithoutRepetition(0, 100, 1)` and `Math.floor(Math.random()*100)`. – Ricardo Marimon Nov 04 '19 at 15:52
  • @brainstorm this approach avoids building the whole array. For example, if you only want 5 numbers in the range 0..1000, this avoids the effort of creating 995 things you are going to discard. – Andy Turner Apr 28 '21 at 05:06
5

In Java 8, if you want to have a list of non-repeating N random integers in range (a, b), where b is exclusive, you can use something like this:

Random random = new Random();
List<Integer> randomNumbers = random.ints(a, b).distinct().limit(N).boxed().collect(Collectors.toList());
rollstuhlfahrer
  • 3,988
  • 9
  • 25
  • 38
  • That's the equivalent of "random.ints(a, b).boxed().distinct().mapToInt(i -> i).limit(N).boxed().collect(...)". Not too eficient. Also, under the hood it is the same implmentation as Vaibhav Jain's, requiring 500500 iterations for 1000 elements. Please take the time to understand the libraries you use. – Torben Feb 19 '19 at 07:58
  • 2
    @Torben Actually, the probability to find the proper random number on each iteration is given by (N-n+1)/N in the Vaibhav Jain implementation. Where *N* is the total number requested random numbers and *n* is the number of current iteration. The expected number of iterations is then given by `O(N log(N))`, which on average is less than 500500. See https://en.wikipedia.org/wiki/Coupon_collector%27s_problem – Slawomir Domagala Feb 21 '19 at 07:05
4

Achintya Jha has the right idea here. Instead of thinking about how to remove duplicates, you remove the ability for duplicates to be created in the first place.

If you want to stick with an array of ints and want to randomize their order (manually, which is quite simple) follow these steps.

  1. create array of size n.
  2. loop through and initialize each value at index i to the value i (or i+1 if you wish to have the numbers 1 to n rather than 0 to n-1).
  3. finally, loop through the array again swapping each value for a value at a random index.

Your code could be modified to look like this:

import java.util.Random;

public class Sort
{
    // use a constant rather than having the "magic number" 10000 scattered about
    public static final int N = 10000;

    public static void main(String[] args)
    {
        //array to store N random integers (0 - N-1)
        int[] nums = new int[N];

        // initialize each value at index i to the value i 
        for (int i = 0; i < nums.length; ++i)
        {
            nums[i] = i;
        }

        Random randomGenerator = new Random();
        int randomIndex; // the randomly selected index each time through the loop
        int randomValue; // the value at nums[randomIndex] each time through the loop

        // randomize order of values
        for(int i = 0; i < nums.length; ++i)
        {
             // select a random index
             randomIndex = randomGenerator.nextInt(nums.length);

             // swap values
             randomValue = nums[randomIndex];
             nums[randomIndex] = nums[i];
             nums[i] = randomValue;
        }
    }
}

And if I were you I would likely break each of these blocks into separate, smaller methods rather than having one large main method.

Hope this helps.

3

If you need generate numbers with intervals, it can be just like that:

Integer[] arr = new Integer[((int) (Math.random() * (16 - 30) + 30))];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
Collections.shuffle(Arrays.asList(arr));
System.out.println(Arrays.toString(arr));`

The result:

[1, 10, 2, 4, 9, 8, 7, 13, 18, 17, 5, 21, 12, 16, 23, 20, 6, 0, 22, 14, 24, 15, 3, 11, 19]

Note:

If you need that the zero does not leave you could put an "if"

user3760016
  • 103
  • 3
0

How about this?

LinkedHashSet<Integer> test = new LinkedHashSet<Integer>();
Random random = new Random();
do{
    test.add(random.nextInt(1000) + 1);
}while(test.size() != 1000);

The user can then iterate through the Set using a for loop.

Jitin Kodian
  • 471
  • 4
  • 14
0

Here we Go!

public static int getRandomInt(int lower, int upper) {
    if(lower > upper) return 0;
    if(lower == upper) return lower;
    int difference = upper - lower;
    int start = getRandomInt();
    
    //nonneg int in the range 0..difference - 1
    start = Math.abs(start) % (difference+1);
    
    start += lower;
    return start;
}

public static void main(String[] args){
    
    List<Integer> a= new ArrayList();
    
    int i;
    int c=0;
    for(;;) {
        c++;
        i= getRandomInt(100, 500000);
        if(!(a.contains(i))) {
            a.add(i);
            if (c == 10000) break;
            System.out.println(i);
        }
        
        
    }
    
    for(int rand : a) {
        System.out.println(rand);
    }
    
    
    
}

Get Random number Returns a random integer x satisfying lower <= x <= upper. If lower > upper, returns 0. @param lower @param upper @return

In the main method I created list then i check if the random number exist on the list if it doesn't exist i will add the random number to the list

It is very slow but straight forward.

yome fisseha
  • 81
  • 1
  • 5
0

If you're using JAVA 8 or more than use stream functionality following way,

Stream.generate(() -> (new Random()).nextInt(10000)).distinct().limit(10000);
Dhwanil Patel
  • 2,273
  • 1
  • 18
  • 28
0
public class RandomNum {
    public static void main(String[] args) {
        Random rn = new Random();
        HashSet<Integer> hSet = new HashSet<>();
        while(hSet.size() != 1000) {
            hSet.add(rn.nextInt(1000));
        }
        System.out.println(hSet);
    }
}
F. Müller
  • 3,969
  • 8
  • 38
  • 49
K D
  • 287
  • 3
  • 10
0

A simple stream solution:

   new Random().ints(0, 10000)
        .distinct()
        .limit(10000)
        .forEach(System.out::println);
olz
  • 116
  • 1
  • 3
-1
public class Randoms {

static int z, a = 1111, b = 9999, r;

public static void main(String ... args[])
{
       rand();
}

    public static void rand() {

    Random ran = new Random();
    for (int i = 1; i == 1; i++) {
        z = ran.nextInt(b - a + 1) + a;
        System.out.println(z);
        randcheck();
    }
}

private static void randcheck() {

    for (int i = 3; i >= 0; i--) {
        if (z != 0) {
            r = z % 10;
            arr[i] = r;
            z = z / 10;
        }
    }
    for (int i = 0; i <= 3; i++) {
        for (int j = i + 1; j <= 3; j++) {
            if (arr[i] == arr[j]) {
                rand();
            }
        }

    }
}
}
Jaap
  • 81,064
  • 34
  • 182
  • 193
-1
HashSet<Integer>hashSet=new HashSet<>();
Random random = new Random();
//now add random number to this set
while(true)
{
    hashSet.add(random.nextInt(1000));
    if(hashSet.size()==1000)
        break;
}
Ori Dar
  • 18,687
  • 5
  • 58
  • 72