224

If I have an enum like this:

public enum Letter {
    A,
    B,
    C,
    //...
}

What is the best way to pick one randomly? It doesn't need to be production quality bulletproof, but a fairly even distribution would be nice.

I could do something like this

private Letter randomLetter() {
    int pick = new Random().nextInt(Letter.values().length);
    return Letter.values()[pick];
}

But is there a better way? I feel like this is something that's been solved before.

3
  • what do you think is wrong with your solution? It looks pretty good to me. Commented Dec 29, 2009 at 0:57
  • 2
    @GregS - the problem is that each call to Letter.values() has to create a new copy of the internal Letter value array. Commented Dec 29, 2009 at 2:13
  • Also not sure if you should be creating a new Random object each time you execute that function. Commented Mar 3, 2021 at 19:21

16 Answers 16

185

The only thing I would suggest is caching the result of values() because each call copies an array. Also, don't create a Random every time. Keep one. Other than that what you're doing is fine. So:

public enum Letter {
  A,
  B,
  C,
  //...

  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));
  }
}
Sign up to request clarification or add additional context in comments.

7 Comments

If you consider it useful, you can make an utility class for doing this. Something like RandomEnum<T extends Enum> with a constructor receiving the Class<T> for creating the list.
I really don't see the point of converting the values() array to an unmodifiable list. The VALUES object is already encapsulated by virtue of being declared private. It would be simpler AND more efficient to make it private static final Letter[] VALUES = ....
Arrays in Java are mutable so if you have a array field and return it in a public method the caller can modify it and it modifies the private filed so you need to defensively copy the array. If you call that method lots of times it can be a problem so you put it in an immutable list instead to avoid unnecessary defensive copying.
@cletus: Enum.values() will return a new array on every invocation, so there is no need to wrap it before passing/using it in other places.
private static final Letter[] VALUES... is OK. It's private so it's inmmutable. You only need the public randomLetter() method which obviously returns a single value. Stephen C is right.
|
173

A single method is all you need for all your random enums:

    public static <T extends Enum<?>> T randomEnum(Class<T> clazz){
        int x = random.nextInt(clazz.getEnumConstants().length);
        return clazz.getEnumConstants()[x];
    }

Which you'll use:

randomEnum(MyEnum.class);

I also prefer to use SecureRandom as:

private static final SecureRandom random = new SecureRandom();

2 Comments

Exactly what I was looking for. I was doing like the accepted answer and that left me with boilerplate code when I needed to randomize from my second Enum. Also, it's easy to forget about SecureRandom sometimes. Thanks.
You read my mind, exactly what I was looking for to add in my random entities generator test class. Thanks for the help
81

Single line

return Letter.values()[new Random().nextInt(Letter.values().length)];

3 Comments

Simple and easy
Should be the most popular answer!
More efficient to not re-create the Random each time. Use ThreadLocalRandom instead. Letter.values()[ThreadLocalRandom.current().nextInt(Letter.values().length)]
49

Combining the suggestions of cletus and helios,

import java.util.Random;

public class EnumTest {

    private enum Season { WINTER, SPRING, SUMMER, FALL }

    private static final RandomEnum<Season> r =
        new RandomEnum<Season>(Season.class);

    public static void main(String[] args) {
        System.out.println(r.random());
    }

    private static class RandomEnum<E extends Enum<E>> {

        private static final Random RND = new Random();
        private final E[] values;

        public RandomEnum(Class<E> token) {
            values = token.getEnumConstants();
        }

        public E random() {
            return values[RND.nextInt(values.length)];
        }
    }
}

Edit: Oops, I forgot the bounded type parameter, <E extends Enum<E>>.

4 Comments

Very old answer I know, but shouldn't that be E extends Enum<E>?
@Lino: Edited for clarity; I don't think it's required for correct type inference of the parameter bound, but I'd welcome correction; note also that new RandomEnum<>(Season.class) is permitted since Java 7.
This single RandomEnum class would be nice as a micro library, if you wanted to bundle it up and publish to central.
19

Simple Kotlin Solution

MyEnum.values().random()

random() is a default extension function included in base Kotlin on the Collection object. Kotlin Documentation Link

If you'd like to simplify it with an extension function, try this:

inline fun <reified T : Enum<T>> random(): T = enumValues<T>().random()

// Then call
random<MyEnum>()

To make it static on your enum class. Make sure to import my.package.random in your enum file

MyEnum.randomValue()

// Add this to your enum class
companion object {
    fun randomValue(): MyEnum {
        return random()
    }
}

If you need to do it from an instance of the enum, try this extension

inline fun <reified T : Enum<T>> T.random() = enumValues<T>().random()

// Then call
MyEnum.VALUE.random() // or myEnumVal.random() 

1 Comment

The question is not tagged as kotlin and is specifically about Java. While nice, this answer doesn't seem to apply to the question at hand.
11
Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)];

Comments

10

Agree with Stphen C & helios. Better way to fetch random element from Enum is:

public enum Letter {
  A,
  B,
  C,
  //...

  private static final Letter[] VALUES = values();
  private static final int SIZE = VALUES.length;
  private static final Random RANDOM = new Random();

  public static Letter getRandomLetter()  {
    return VALUES[RANDOM.nextInt(SIZE)];
  }
}

Comments

6

It's probably easiest to have a function to pick a random value from an array. This is more generic, and is straightforward to call.

<T> T randomValue(T[] values) {
    return values[mRandom.nextInt(values.length)];
}

Call like so:

MyEnum value = randomValue(MyEnum.values());

Comments

6

Here a version that uses shuffle and streams

List<Direction> letters = Arrays.asList(Direction.values());
Collections.shuffle(letters);
return letters.stream().findFirst().get();

Comments

5

This is probably the most concise way of achieving your goal.All you need to do is to call Letter.getRandom() and you will get a random enum letter.

public enum Letter {
    A,
    B,
    C,
    //...

    public static Letter getRandom() {
        return values()[(int) (Math.random() * values().length)];
    }
}

Comments

3

If you do this for testing you could use Quickcheck (this is a Java port I've been working on).

import static net.java.quickcheck.generator.PrimitiveGeneratorSamples.*;

TimeUnit anyEnumValue = anyEnumValue(TimeUnit.class); //one value

It supports all primitive types, type composition, collections, different distribution functions, bounds etc. It has support for runners executing multiple values:

import static net.java.quickcheck.generator.PrimitiveGeneratorsIterables.*;

for(TimeUnit timeUnit : someEnumValues(TimeUnit.class)){
    //..test multiple values
}

The advantage of Quickcheck is that you can define tests based on a specification where plain TDD works with scenarios.

2 Comments

looks intriguing. I'll have to give it a try.
You can mail me if something does not work. You should use the 0.5b version.
3

I guess that this single-line-return method is efficient enough to be used in such a simple job:

public enum Day {
    SUNDAY,
    MONDAY,
    THURSDAY,
    WEDNESDAY,
    TUESDAY,
    FRIDAY;

    public static Day getRandom() {
        return values()[(int) (Math.random() * values().length)];
    }

    public static void main(String[] args) {
        System.out.println(Day.getRandom());
    }
}

Comments

2

It´s eaiser to implement an random function on the enum.

public enum Via {
    A, B;

public static Via viaAleatoria(){
    Via[] vias = Via.values();
    Random generator = new Random();
    return vias[generator.nextInt(vias.length)];
    }
}

and then you call it from the class you need it like this

public class Guardia{
private Via viaActiva;

public Guardia(){
    viaActiva = Via.viaAleatoria();
}

Comments

1

I would use this:

private static Random random = new Random();

public Object getRandomFromEnum(Class<? extends Enum<?>> clazz) {
    return clazz.values()[random.nextInt(clazz.values().length)];
}

1 Comment

did you actually try that? Enum does not have the values() method.
0

enum ShapeColor { Blue, Yellow, Red, Green, White, }

    Random random=new Random();
    ShapeColor[] values=ShapeColor.values();
    int size=values.length;
    return values[random.nextInt(size)];

2 Comments

Can you explain how it works and why your answer fix the issue ?
Sure, let me explain. First, we convert the enum into an array of the enum type. Now all values of the enum would be stored in an array. Then we generate a random int with max bound as the size of an array to generate a random index. Finally, after getting a random index, we access the value at that particular index from an array of the enum type.
-1
public static Letter randomLetter() {
    return List.of(values()).get(Random.randomInt(List.of(values()).size()));

}

1 Comment

Random.randomInt is not static

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.