5

How would i prevent duplicating numbers from random numbers. I need to generate 5 numbers between 1 and 9 that are each different. I would often get same numbers like 23334, how can i prevent that? Any help would be great!

    int num2 = (int) Math.round((Math.random()*9) +1);
    int num1 = (int) Math.round((Math.random()*9) +1);
    int num5 = (int) Math.round((Math.random()*9) +1);
    int num3 = (int) Math.round((Math.random()*9) +1);
    int num4 = (int) Math.round((Math.random()*9) +1);
Jim Lewis
  • 43,505
  • 7
  • 82
  • 96
Marcus Liu
  • 59
  • 2
  • 4
  • 3
    Add to a Set. – Jared Burrows Jan 20 '15 at 05:32
  • FYI: If your range is only 1-9, you should expect this with random numbers. There's a pretty high likelihood that you'll get duplicates. – Nate Barbettini Jan 20 '15 at 05:33
  • For small sets of small ranges, a permutation is probably best. For big ranges, you can make a set of already chosen values and retry as needed. For big ranges when you need bounded worst-case behavior, you need to choose n different random values in [1,m], [1,m-1], ... [1,m-n+1] and then do fix-up. – Jeff Jan 20 '15 at 07:06

8 Answers8

8

One option is to use shuffle algorithm (e.g. Fisher-Yates shuffle ) to generate random sequence from 1 to 9, then take first 5 numbers of the sequence

Further explanation on StackOverflow: https://stackoverflow.com/a/196065/950427

Community
  • 1
  • 1
Phuong Nguyen
  • 2,960
  • 1
  • 16
  • 25
  • I doubt generation sequence 1-N, shufle to find random 5 is more efficient if you need 5 of 0-1000000 – StanislavL Jan 20 '15 at 05:45
  • you can modify the Fisher-Yates shuffle algorithm to stop the algorithm immediately after you already find first 5 numbers – Phuong Nguyen Jan 20 '15 at 05:46
  • But anyway I have to allocate memory (an array) to generate the sequence? – StanislavL Jan 20 '15 at 05:49
  • There's a variation "inside out" of the algorithm in the wiki page, where the shuffle doesn't modify the source array, so the source array doesn't need to be allocated in advanced, and can use simple index instead. I'll try to post a sample code – Phuong Nguyen Jan 20 '15 at 06:00
  • for common case of course you need some elaborated solution but if you can shown on screen just 5 elements from limited list it's better to use *faster to implement* rather than *more efficient in common case* approach – StanislavL Jan 20 '15 at 06:04
6
Set<Integer> set=new HashSet<>();
while (set.size()<5) {
    set.add( Math.round((Math.random()*9) +1));
}

After the set is filled you have 5 unique random numbers.

UPDATE: just to illustrate Jared Burrows' comment

StanislavL
  • 56,971
  • 9
  • 68
  • 98
1
  1. Create a List includes the numbers that you want (1 to 9).
  2. Generate random number from 0 to (size of the list minus 1).
  3. Remove one element by index from the above generated random number. And add the removed element to a array which to be returned as a results

    public static void main(String[] args) {
         int []answers= returnRandomNonRepeatingNumbers(5,0,9);
         for(int answer: answers) {
            System.out.println(answer);
         }
    }
    public static int[] returnRandomNonRepeatingNumbers(int sizeYouWant, int poolStart, int poolEnd) {
        List<Integer> pool=new ArrayList<Integer>();
        for(int i=poolStart;i<=poolEnd;i++) {
           pool.add(i);
        }
    
        int []answers=new int[sizeYouWant];
    
        for(int i=0;i<sizeYouWant;i++) {
            //random index to be pick and remove from pool
            int randomIndex = (int) Math.round((Math.random()*(pool.size()-1)));
            answers[i]=pool.remove(randomIndex);
        }
    
        return answers;
    }
    
1

If the number of possible random values is small, you want to use shuffle.

List<Integer> values = IntStream.range(0, 10).boxed().collect(toList());
Collections.shuffle(values);
values = values.subList(0, 5);

If the number of possible random values is large, you want to test adding them to a Set (or the original list if small enough)

Set<Integer> valueSet = new HashSet<>(); 
Random rand = new Random();
while(valuesSet.size() < 5) valuesSet.add(rand.nextInt(9) + 1);
List<Integer> values = new ArrayList<>(valueSet);
Collections.shuffle(values, rand);

Note: you need to shuffle the set as it doesn't preserve order. e.g. the numbers 1,2,3 will always come out in that order with HashSet, not 3,2,1.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

Floyd's subset selection algorithm is designed to do exactly what you want, and is extremely efficient even for large sets. Selecting m items from a set of n is O(m) average running time, independent of n. Here's a Java implementation.

/*
 * Floyd's algorithm to chose a random subset of m integers
 * from a set of n, zero-based.
 */
public static HashSet<Integer> generateMfromN(int m, int n) {
   HashSet<Integer> s = new HashSet<Integer>();
   for (int j = n-m; j < n; ++j) {
      if(! s.add((int)((j+1) * Math.random()))) {
         s.add(j);
      }
   }
   return s;
}
pjs
  • 18,696
  • 4
  • 27
  • 56
0

I suppose you would need to store the ones that have been generated into an array and compare the new random number to the list to ensure it is unique.

public static void main (String[] args) throws java.lang.Exception
{
    // your code goes here
    int[] numbers = new int[5];
    int tempNumber = 0;

    for(int numberCounter = 0; numberCounter < numbers.length;)
    {
        tempNumber = (int) Math.round((Math.random()*9) +1);

        if(!contains(numbers, tempNumber)){
            numbers[numberCounter++] = tempNumber;
        }
    }
}

public static boolean contains(final int[] numbersArray, final int tempNumber) {
    for (final int numberFromArray : numbersArray) {
        if (numberFromArray == tempNumber) {
            return true;
        }
    }
    return false;
} 

I notice you did not use an array in your example, so in case you do not know how to use them yet, you could also make 5 variables.

int randomNumber = 0;

int firstNumber = Math.round((Math.random()*9) +1);
int secondNumber = 0;

while(secondNumber == 0){
    randomNumber = Math.round((Math.random()*9) +1)l
    if(randomNumber != firstNumber){
        secondNumber = randomNumber;
    }
}

And you could continue making while statements like that. But if you are supposed to know about arrays, you should definitely be using one to store the numbers.

sauv0168
  • 93
  • 8
0

One possible approach to this problem can be divide & conquer. Step of following describes the approach:

  1. Say m is the minimum & n is the maximum, within what i wanna get x number of randoms
  2. Choose a random p between m & n. Save it to an array of answer. decrease x by 1 as we get one answer to our problem.
  3. Now take a q a random number between m & p-1, another r a random number between p+1 & n. Fill up the answer array with q & r decrease x 1 for q and another 1 for the r.
  4. Now carry on this process recursively, until the lower bound (m) & higher bound (n) becomes equal or x becomes 0.

Benefit: benefit of this approach is that, in worst case, it's runtime will be O(x), where x is the number of random number required. The best case scenarion is also o(x), as i have to find at least n number of random. These two comprise average case to θ(x) complexity.

import java.util.Random;
class GenerateDistinctRandom{
static int alreadyPut = 0;
static Random rand = new Random();

    public static int[] generateDistinctRandom(int howMany, int rangeMin, int rangeMax)
    {
        int randomNumbers[] = new int[howMany]; 
        GenerateDistinctRandom.recursiveRandomGenerator(rangeMin, rangeMax, randomNumbers, howMany);
        return randomNumbers;
    }

    private static void recursiveRandomGenerator(int rangeMin, int rangeMax, int[] storage ,int storageSize)
    {
        if(rangeMax - rangeMin <= 0 || GenerateDistinctRandom.alreadyPut == storageSize)
        {
            return ;
        }

    int randomNumber = GenerateDistinctRandom.rand.nextInt(rangeMax-rangeMin) + rangeMin;
    storage[GenerateDistinctRandom.alreadyPut] = randomNumber;
    GenerateDistinctRandom.alreadyPut++;

    //calling the left side of the recursion
    recursiveRandomGenerator(rangeMin, randomNumber - 1, storage, storageSize);
    recursiveRandomGenerator(randomNumber + 1, rangeMax, storage, storageSize);     
    }

    public static void main(String []args){
        int howMany = 5;
        int distinctNumber[] = GenerateDistinctRandom.generateDistinctRandom(howMany 0, 9);

        for(int i = 0;i < howMany;i++)
        {
            System.out.println(distinctNumber[i]);
        }

    }
}
Ratul Sharker
  • 7,484
  • 4
  • 35
  • 44
0

How about this?

package com.se;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class TestRandom {

    List<Integer> comp = new ArrayList<>();
    int listSize = 20;
    public void doTask() {

        Random ran = new Random();
        int i = 0;
        while(i < listSize){
            int randomNumber = ran.nextInt(80) + 1;

            if(!comp.contains(randomNumber)){
               comp.add(randomNumber);
               i++;
            }
        }

    for(Integer num : comp){
        System.out.println(num);
    }
}

public static void main(String[] args) {
    TestRandom testRandom = new TestRandom();
    testRandom.doTask();
}

}
muasif80
  • 5,586
  • 4
  • 32
  • 45