0

Here's the code I have that solves my problem. But it seems really brute forced. Is there any optimized/elegant way to write this?

System.out.println("\n\nPart II: Let' put in a list of 50 random numbers between 10 to 99. No Duplicates!");

        Linkedlist l1 = new Linkedlist();
        Random rand = new Random(); 

        for(int i = 0; i < 50; i++){
            int num = rand.nextInt(89) + 10;//range between 10 and 99.
            while(true){
                if(!l1.search(num)){
                    l1.add(num);
                    break;
                }
                else
                    num = rand.nextInt(89) + 10;//recycle for new num 
            }//infinite loop until new non-duplicate random value is generated for the list. 

        }//for
Rajendra arora
  • 2,186
  • 1
  • 16
  • 23
wonghenry
  • 575
  • 2
  • 6
  • 18

6 Answers6

7

Well there is a more cleaner way to do this that doesn't involve randomizing so much and output rejection. You can populate a List with the numbers you require, in this case:

List<Integer> numberList = new ArrayList<>();
for(int i=11; i<=99; i++){
    numberList.add(i);    
}

Then shuffle the List and pick first N numbers from it..

Collections.shuffle(numberList);
for(int j=0; j<50; j++){
    System.out.println(numberList.get(j));
}

You have to know your set in advance though to be able to populate it.

Dropout
  • 13,653
  • 10
  • 56
  • 109
  • Good approach mate. I personally liked it. But I think it would not be good if the required list in more than 1000? – Ankur Shanbhag Feb 10 '14 at 07:11
  • "doesn't involve randomizing so much", uh, yes it does. What do you think `shuffle()` does? – hyde Feb 10 '14 at 07:22
  • @AnkurShanbhag it depends.. The thing that pushes the original way back is the fact that if you have to pick N-1 elements from an N-sized array you will have too much rejected outputs.. I my case it's the fact that you have to shuffle the whole set.. I agree with you, but in this case it's probably more efficient. – Dropout Feb 10 '14 at 07:26
  • @Dropout: Yes it is more efficient if the size of the list is small. Anyways +1 for the approach. :-) – Ankur Shanbhag Feb 10 '14 at 07:36
  • @Dropout Shuffle is 100% about randomizing, so I don't think it's accurate to say, that anything using shuffle doesn't involve "so much" randomizing. – hyde Feb 10 '14 at 07:37
  • @hyde please think about an example where you have a relatively large set and you pick all but one of it's elements. It may involve more than 100% shuffling.. That's the drawback of rejecting randomized numbers in case of no-repetition scenario. – Dropout Feb 10 '14 at 07:43
  • @Dropout, the drawback to your approach is when you're selecting a relatively small number of samples out of a large collection. In that case, the time spent shuffling the entire collection is largely wasted. – gdejohn Feb 10 '14 at 07:49
5

Bounded Fisher-Yates shuffle. Runtime for the random sampling is linear in the number of elements you need, not the number of elements you're picking from. You don't waste any time shuffling the entire range of elements or rejecting elements that have already been picked.

int[] sample(int sampleSize, int startInclusive, int endExclusive) {
    int[] samples = new int[sampleSize];
    int[] range = IntStream.range(startInclusive, endExclusive).toArray();
    Random random = new Random();
    for (int i = 0, j = range.length; i < samples.length; i++) {
        int k = random.nextInt(j--);
        samples[i] = range[k];
        range[k] = range[j];
    }
    return samples;
}
gdejohn
  • 7,451
  • 1
  • 33
  • 49
3

I would prefer using Set instead of a List as Set will automatically handle duplicates so that we need to worry about eliminating them by our own.

Try this:

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

    Random rand = new Random();

    while(true) {
        int num = rand.nextInt(89) + 10;// range between 10 and 99.
        set.add(num);
        if (set.size() == 50) {
            break;
        }
    }
    System.out.println(set);
Ankur Shanbhag
  • 7,746
  • 2
  • 28
  • 38
2

Sets don't allow duplicates:

Set<Integer> s = new HashSet<Integer>();
Random rand = new Random();
while (s.size() < 50) {
    int num = rand.nextInt(89) + 10;// range between 10 and 99.
    s.add(num);
}
orlandocr
  • 313
  • 2
  • 8
  • 1
    This approach wastes time rejecting elements that have already been picked. It's conceptually simple, but can end up being very inefficient when `n/m` gets close to 1 (picking `n` out of `m`). – gdejohn Feb 10 '14 at 07:43
1

You could just use a Set, which will only allow unique values to be stored in it, this way you could just keep looping while the number of elements is less than 50...

Set<Integer> nums = new HashSet<>(50);
while (nums.size() < 50) {
    nums.add((int)(10 + (Math.random() * 89)));
}

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

This is a variation on @AnkurShanbhag's answer (I don't like while (true) loops ;)), so if you like, shoot them credit ;)

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
0
    package com.project.stackoverflow;

import java.util.Random;
import java.util.Scanner;
import java.util.TreeSet;

public class RandomGenerator {

    private Scanner s;

    public TreeSet<Integer> compute() {
        TreeSet<Integer> generatedList = new TreeSet<Integer>();
        s = new Scanner(System.in);
        System.out.println("Enter the lower bound for checking random numbers:");
        long lowBound = s.nextLong();
        System.out.println("Enter the upper bound for checking random numbers:");
        long topBound = s.nextLong();
        Random randomNumbers = new Random();
        for (int i = 0; i < topBound; i++) {
            if (generatedList.size() == 5) {
                break;
            } else {
                generatorFunc(lowBound, topBound, randomNumbers, generatedList);
            }
        }
        return generatedList;
    }

    public void generatorFunc(long lowBound, long topBound, Random randomNumbers, TreeSet<Integer> generatedList) {
        long limit = topBound - lowBound;
        long part = (long) (limit * randomNumbers.nextDouble());
        int randomNum = (int) (part + lowBound);
        generatedList.add(randomNum);
    }

    public void printList() {
        TreeSet<Integer> testListVals = compute();
        System.out.println("New" + testListVals);
    }

    public static void main(String[] args) {
        RandomGenerator obj = new RandomGenerator();
        obj.printList();
    }
}
Bhaskar
  • 337
  • 6
  • 21