How can I pick a random enum when everyone has different probabilities?

Viewed 208

I know here in stackoverflow there is already a question about how to randomly select an enum. In the example code, every letter has the same probability of being selected. But how would I rewrite the code when not every enum has the same probability? For example: A has a probability of 50%, B of 30%, C of 15% and D of 5%.

public enum Letter {
  A,
  B,
  C,
  D;

  private static final List<Letter> VALUES =
    Collections.unmodifiableList(Arrays.asList(values()));
  private static final int SIZE = VALUES.size();
  private static final Random RANDOM = new Random();

  public static Letter randomLetter()  {
    return VALUES.get(RANDOM.nextInt(SIZE));
  }
}
2 Answers

This is a way associating each enum value with a probability range, then fitting a random number in the range to select a value:

enum Letter {
    A(0, 51), B(51, 81), C(81, 96), D(95, 101);

    private int probStart;
    private int probEnd;

    private static final Random RANDOM = new Random();

    Letter(int s, int e) {
        this.probStart = s;
        this.probEnd = e;
    }

    public static Letter randomLetter() {
        int pick = RANDOM.nextInt(100);
        return Arrays.stream(values())
                .filter(v -> pick >= v.probStart && pick < v.probEnd)
                .findAny()
                .get();
    }
}

Of course you can choose to cache these probabilities in a map, but an implementation like the one above (based on percent scales) may just seem to create too large a map for the search to be undesirable.

A few tests produced successively these sets of 100 selections:

{A=56, B=26, C=14, D=4}
{A=39, B=39, C=18, D=4}
{A=51, B=30, C=13, D=6}
Related