217

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.

Lii
  • 11,553
  • 8
  • 64
  • 88
Nick Heiner
  • 119,074
  • 188
  • 476
  • 699

16 Answers16

178

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));
  }
}
cletus
  • 616,129
  • 168
  • 910
  • 942
  • 8
    If you consider it useful, you can make an utility class for doing this. Something like RandomEnum with a constructor receiving the Class for creating the list. – helios Dec 29 '09 at 01:16
  • 18
    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 = ...`. – Stephen C Dec 29 '09 at 01:56
  • 5
    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 Dec 29 '09 at 02:48
  • 2
    @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. – Chii Dec 29 '09 at 08:21
  • @Chii: it's precisely because it returns an array every time that you should create an immutable copy. – cletus Dec 29 '09 at 08:52
  • 5
    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. – helios Dec 29 '09 at 14:11
  • Arrays are mutable and it is just a way to prevent the array from being modifiable. Another option would be to have `Letter[] VALUES = values();` inside `randomLetter()` but this will remove the "caching" suggested in @cletus answer – chris Apr 20 '22 at 20:20
167

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();
zudduz
  • 2,457
  • 5
  • 24
  • 29
Eldelshell
  • 6,683
  • 7
  • 44
  • 63
  • 1
    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. – Siamaster Jul 30 '18 at 10:43
  • You read my mind, exactly what I was looking for to add in my random entities generator test class. Thanks for the help – Roque Sosa Apr 09 '20 at 20:26
76

Single line

return Letter.values()[new Random().nextInt(Letter.values().length)];
Daniel Fath
  • 16,453
  • 7
  • 47
  • 82
Mohamed Taher Alrefaie
  • 15,698
  • 9
  • 48
  • 66
  • 2
    Simple and easy – CJDownUnder Feb 16 '21 at 04:01
  • 5
    Should be the most popular answer! – Zoette Mar 23 '21 at 02:18
  • More efficient to not re-create the `Random` each time. Use [`ThreadLocalRandom`](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/util/concurrent/ThreadLocalRandom.html) instead. `Letter.values()[ThreadLocalRandom.current().nextInt(Letter.values().length)]` – Basil Bourque Aug 31 '23 at 22:19
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>>.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 1
    See also [*Class Literals as Runtime-Type Tokens*](http://docs.oracle.com/javase/tutorial/extra/generics/literals.html). – trashgod Jul 06 '13 at 13:01
  • 1
    Very old answer I know, but shouldn't that be `E extends Enum`? – Lino Aug 14 '18 at 05:38
  • 1
    @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. – trashgod Aug 14 '18 at 16:25
  • This single `RandomEnum` class would be nice as a micro library, if you wanted to bundle it up and publish to central. – Greg Chabala Oct 13 '19 at 17:08
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() 
Gibolt
  • 42,564
  • 15
  • 187
  • 127
  • 1
    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. – E-Riz Nov 30 '22 at 15:08
11
Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)];
Anatoly Shamov
  • 2,608
  • 1
  • 17
  • 27
anonymous
  • 111
  • 1
  • 2
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)];
  }
}
Deepti
  • 934
  • 12
  • 18
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());
Joseph Thomson
  • 9,888
  • 1
  • 34
  • 38
6

Here a version that uses shuffle and streams

List<Direction> letters = Arrays.asList(Direction.values());
Collections.shuffle(letters);
return letters.stream().findFirst().get();
major seitan
  • 61
  • 1
  • 1
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)];
    }
}
Adilli Adil
  • 1,231
  • 1
  • 17
  • 25
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.

Thomas Jung
  • 32,428
  • 9
  • 84
  • 114
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());
    }
}
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();
}
Folea
  • 29
  • 5
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)];
}
Konstantin Pavlov
  • 956
  • 1
  • 10
  • 24
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)];
  • Can you explain how it works and why your answer fix the issue ? – Elikill58 Oct 25 '21 at 14:12
  • 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. – Zeeshan Liaqat Oct 26 '21 at 05:36
-1
public static Letter randomLetter() {
    return List.of(values()).get(Random.randomInt(List.of(values()).size()));

}
Ian Campbell
  • 23,484
  • 14
  • 36
  • 57
Izzy
  • 1
  • 2