1

I need to make a typical integer filled array with 10 random non repeating numbers from 0 to 20. Also, I need to be able to modify this so I can exclude some random numbers from 0 to 20.

How can I do this?

0

6 Answers 6

15

You can do this in three easy steps:

  1. Build a list with all the candidate numbers you want
  2. Use Collections.shuffle to shuffle that list
  3. Use the n first elements of that shuffled list.
Sign up to request clarification or add additional context in comments.

Comments

4

First build a list of size 20 with values 0,...,19
Then shuffle() it
And last - take the sublist containing first 10 elements.

Comments

4

This Method will work for you. It generate 10 unique random numbers from 0 to 20.

public static int[] getRandomArray(){
   int randomCount =10;
   int maxRandomNumber = 21;
   if(randomCount >maxRandomNumber ){
         /* if randomCount is greater than maxRandomNumber
          * it will not be possible to generate randomCount 
          * unique numbers 
          **/
          return null;
    }
    HashMap<Integer, Integer> duplicateChecker = new HashMap<Integer, Integer>();
    int[] arr = new int[randomCount ];
    int i = 0;
    while(i<randomCount ){
        // Generate random between 0-20, higher limit 21 is excluded
        int random = new Random().nextInt(maxRandomNumber );
        if(duplicateChecker.containsKey(random)==false){
            duplicateChecker.put(random, random);
            arr[i]=random;
            i++;
        }
    }
    return arr;
}

* Edited: To make the method deterministic. And Avoid the chance of infinite loop

public static int[] getRandomArray(){
    int randomCount =10;
    int maxRandomNumber = 21;
    if(randomCount >maxRandomNumber ){
        /* if randomCount is greater than maxRandomNumber
         * it will not be possible to generate randomCount 
         * unique numbers 
         **/
        return null;
    }
    ArrayList<Integer> arrayList = new ArrayList<Integer>();
    // Generate an arrayList of all Integers
    for(int i=0;i<maxRandomNumber;i++){
        arrayList.add(i);
    }
    int[] arr = new int[randomCount ];
    for(int i=0;i<randomCount;i++){
        // Generate random between 0-20, higher limit 21 is excluded
        int random = new Random().nextInt(arrayList.size());
        // Remove integer from location 'random' and assign it to arr[i]
        arr[i]=arrayList.remove(random);        
    }
    return arr;
}

9 Comments

Well, theoretically this isn't guaranteed to terminate. Its runtime is not deterministic.
@Mat it will stop because Random.nextInt distributes number uniformly(more or less) besides every number must be eventually drawn
It will stop at some point. But that point might be after megaquazillions of iterations given proper alignment of the stars. Runtime is not deterministic.
@Trismegistos: Can you give a specific n such that the algorithm will make less then n iterations? If the answer is no [and it is] - the algorithm's run time is not bounded and thus run time on worst case analyzis is O(infinity)
@Mat, I have added the code to ensure that the loop will not be infinite. Hope it will work fine now.
|
2

What about making an arraylist of numbers upto 20, and after each random number call you remove the number from the list and into the array.

example

Random r = new Random();
int[] myArray = new int[10];
ArrayList<Integer> numsToChoose = new ArrayList<Integer>();

int counter = 0;

for(int i = 0; i < 21; i++)
{
    numsToChoose.add(i);
}

while(numsToChoose.size() > 11)
{
    myArray[counter] = numsToChoose.remove(r.nextInt(numsToChoose.size()));
    counter++;
}

That way it should only loop 10 times, I may be wrong though. Hope it helps

EDIT: And in order to modify this to exclude certain numbers, you would just need a method that takes an array that contains said numbers as a parameter, and loop through it removing each number from the arraylist before you generate your random numbers.

Comments

1

Most of the other responses offer the Collections.shuffle method as a solution. Another way, which is theoretically faster is the following:

First lets build the list:

public class RandomWithoutReplacement {
        private int [] allowableNumbers;

        private int totalRemaining;

        /**
         * @param upperbound the numbers will be in the range from 0 to upperbound (exclusive).
         */
        public RandomWithoutReplacement ( int upperbound ) {
               allowableNumbers = new int[ upperbound ];
               for (int i = 0; i < upperbound; i++) {
                   allowableNumbers[i] = i;
               }
               totalRemaining = upperbound;
        }
 }

Next lets consider what we need to do when we need to get the next number.

1) When we request another number, it must be chosen from any one of the available, uniformly.

2) Once it is chosen, it must not repeat again.

Here is what we can do: First, choose a number at random from the allowableNumbers array. Then, remove it from the array. Then remove the number at the end of the array, and place it in the position of the number we are to return. This ensures all of the 2 conditions we have placed.

      public int nextRandom () {
           //Get a random index
           int nextIndex = (int) ( Math.random() * totalRemaining );
           //Get the value at that index
           int toReturn = allowableNumbers [ nextIndex ];
           //Find the last value
           int lastValue = allowableNumbers [ totalRemaining - 1 ];
           //Replace the one at the random index with the last one
           allowableNumbers[ nextIndex ] = lastValue;
           //Forget about the last one
           totalRemaining -- ;

           return toReturn;
      }

With that, your function is almost complete.

I would add a couple more things just in case:

      public boolean hasNext () {
            return totalRemaining > 0;
      }

And at the beginning of the actual function:

      public int nextRandom () {
             if (! hasNext() )
                 throw new IllegalArgumentException();
             // same as before...
      }

That should be it!

3 Comments

I do not see how this method is faster than Collections.shuffle. Collection shuffle may works exacly same way but it will use less memory because after it shuffled the array it may get rid off totalRemaining variable. Additionaly your class allocates some array of N number but user will need array of those number so he will allocate his own array of N number so memory constraint is at least 2*N whether Collections.shuffle works in place so it will not allocate any additional memory -- Array of size N is enought plus some addidtional local variables same as in your class.
If you read the Collection.shuffle documentation, you'll see that it takes linear time to shuffle, which adds onto the linear time that it takes to construct. Furthermore, it is incorrect that the memory usage is at least 2*N. It is actually at most 2*N because the user will need at most N random numbers. I guess my approach is better if the user wants a small random subset, and the Collections.shuffle approach is better if the user wants a large random subset.
I didn't count local variables so it is at leas 2*N * sizeof(int) bytes.
0

Well, I could't help it not to post my solution which is storing a sequance of numbers into twice as many random locations first. Then compacts it into the resultting array.

int[] myRandomSet = generateNumbers(20, 10);

...

public int[] generateNumbers(int range, int arrayLenght){
    int tempArray[];
    int resultArray[];
    int doubleLocations;
    Random generator = new Random();

    doubleLocations = range * 2;
    tempArray = new int[doubleLocations];
    resultArray = new int[arrayLenght];

    for (int i=1; i<=range; i++){   
        if (i != 5 && i != 13){  //exclude some numbers
            do{
                r = generator.nextInt(doubleLocations); 
            }while(tempArray[r]!=0);
            tempArray[r] = i; //enter the next number from the range into a random position
        }
    }

    int k = 0;
    for (int i=0; i<(doubleLocations); i++){
        if(tempArray[i] != 0){
            resultArray[k] = tempArray[i]; //compact temp array
            k++;
            if (k == arrayLenght) break;
        }
    }

    return resultArray;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.