Creating random numbers with no duplicates

后端 未结 18 2185
忘了有多久
忘了有多久 2020-11-21 12:00

In this case, the MAX is only 5, so I could check the duplicates one by one, but how could I do this in a simpler way? For example, what if the MAX has a value of 20? Thanks

18条回答
  •  南旧
    南旧 (楼主)
    2020-11-21 12:26

    The simplest way would be to create a list of the possible numbers (1..20 or whatever) and then shuffle them with Collections.shuffle. Then just take however many elements you want. This is great if your range is equal to the number of elements you need in the end (e.g. for shuffling a deck of cards).

    That doesn't work so well if you want (say) 10 random elements in the range 1..10,000 - you'd end up doing a lot of work unnecessarily. At that point, it's probably better to keep a set of values you've generated so far, and just keep generating numbers in a loop until the next one isn't already present:

    if (max < numbersNeeded)
    {
        throw new IllegalArgumentException("Can't ask for more numbers than are available");
    }
    Random rng = new Random(); // Ideally just create one instance globally
    // Note: use LinkedHashSet to maintain insertion order
    Set generated = new LinkedHashSet();
    while (generated.size() < numbersNeeded)
    {
        Integer next = rng.nextInt(max) + 1;
        // As we're adding to a set, this will automatically do a containment check
        generated.add(next);
    }
    

    Be careful with the set choice though - I've very deliberately used LinkedHashSet as it maintains insertion order, which we care about here.

    Yet another option is to always make progress, by reducing the range each time and compensating for existing values. So for example, suppose you wanted 3 values in the range 0..9. On the first iteration you'd generate any number in the range 0..9 - let's say you generate a 4.

    On the second iteration you'd then generate a number in the range 0..8. If the generated number is less than 4, you'd keep it as is... otherwise you add one to it. That gets you a result range of 0..9 without 4. Suppose we get 7 that way.

    On the third iteration you'd generate a number in the range 0..7. If the generated number is less than 4, you'd keep it as is. If it's 4 or 5, you'd add one. If it's 6 or 7, you'd add two. That way the result range is 0..9 without 4 or 6.

提交回复
热议问题