Si j'ai un enum comme ça:
public enum Letter {
A,
B,
C,
//...
}
Quelle est la meilleure façon de choisir un au hasard? Il n’est pas nécessaire que la qualité de production soit optimale, mais une distribution assez égale serait Nice.
Je pourrais faire quelque chose comme ça
private Letter randomLetter() {
int pick = new Random().nextInt(Letter.values().length);
return Letter.values()[pick];
}
Mais y a-t-il une meilleure façon? J'ai l'impression que c'est quelque chose qui a été résolu avant.
La seule chose que je suggérerais est de mettre en cache le résultat de values()
parce que chaque appel copie un tableau. Aussi, ne créez pas un Random
à chaque fois. Gardez-en un. Autre que ce que vous faites est bien. Alors:
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));
}
}
Une seule méthode suffit pour tous vos énumérations aléatoires:
public static <T extends Enum<?>> T randomEnum(Class<T> clazz){
int x = random.nextInt(clazz.getEnumConstants().length);
return clazz.getEnumConstants()[x];
}
Que vous utiliserez:
randomEnum(MyEnum.class);
Je préfère aussi utiliser SecureRandom en tant que:
private static final SecureRandom random = new SecureRandom();
Combinant les suggestions de cletus et 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: Oups, j'ai oublié le paramètre de type borné, <E extends Enum<E>>
.
Une seule ligne
return Letter.values()[new Random().nextInt(Letter.values().length)];
D'accord avec Stphen C & helios. Le meilleur moyen de récupérer un élément aléatoire d’Enum est:
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)];
}
}
Voici une version qui utilise shuffle et stream
List<Direction> letters = Arrays.asList(Direction.values());
Collections.shuffle(letters);
return letters.stream().findFirst().get();
C’est probablement le moyen le plus concis d’atteindre votre objectif. Il vous suffit d’appeler Letter.getRandom()
pour obtenir une lettre au hasard.
public enum Letter {
A,
B,
C,
//...
public static Letter getRandom() {
return values()[(int) (Math.random() * values().length)];
}
}
Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)];
Il est probablement plus facile d'avoir une fonction qui sélectionne une valeur aléatoire dans un tableau. Ceci est plus générique, et est simple à appeler.
<T> T randomValue(T[] values) {
return values[mRandom.nextInt(values.length)];
}
Appelle comme ça:
MyEnum value = randomValue(MyEnum.values());
Si vous faites cela pour les tests, vous pouvez utiliser Quickcheck ( c'est un Java le port sur lequel j'ai travaillé ).
import static net.Java.quickcheck.generator.PrimitiveGeneratorSamples.*;
TimeUnit anyEnumValue = anyEnumValue(TimeUnit.class); //one value
Il supporte tous les types primitifs, composition de type, collections, différentes fonctions de distribution, bornes, etc. Il prend en charge les coureurs exécutant plusieurs valeurs:
import static net.Java.quickcheck.generator.PrimitiveGeneratorsIterables.*;
for(TimeUnit timeUnit : someEnumValues(TimeUnit.class)){
//..test multiple values
}
L’avantage de Quickcheck est que vous pouvez définir des tests basés sur un spécification où TDD simple fonctionne avec des scénarios.
Il est plus facile d'implémenter une fonction aléatoire sur l'énumération.
public enum Via {
A, B;
public static Via viaAleatoria(){
Via[] vias = Via.values();
Random generator = new Random();
return vias[generator.nextInt(vias.length)];
}
}
et puis vous l'appelez de la classe dont vous avez besoin comme ça
public class Guardia{
private Via viaActiva;
public Guardia(){
viaActiva = Via.viaAleatoria();
}
Je voudrais utiliser ceci:
private static Random random = new Random();
public Object getRandomFromEnum(Class<? extends Enum<?>> clazz) {
return clazz.values()[random.nextInt(clazz.values().length)];
}