从枚举中选择一个随机值?

如果我有一个这样的enum:

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

随机挑选一个的最佳方法是什么?它不需要是生产质量的防弹,但一个相当均匀的分布会很好。

我可以这样做

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

但是有没有更好的办法呢?我觉得这个问题之前已经解决了。

217317 次浏览

我唯一的建议是缓存values()的结果,因为每次调用都会复制一个数组。另外,不要每次都创建Random。保持一个。除此之外,你做得很好。所以:

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));
}
}

结合克里特斯赫利俄斯的建议,

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)];
}
}
}

编辑:哎呀,我忘了有界类型参数,<E extends Enum<E>>

如果你这样做是为了测试你可以使用Quickcheck (这是我一直在做的一个Java端口)。

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


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

它支持所有的基本类型,类型组合,集合,不同的分布函数,边界等。它支持运行器执行多个值:

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


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

Quickcheck的优点是你可以基于规范定义测试,其中普通的TDD与场景一起工作。

Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)];

一个方法就是你需要的所有随机枚举:

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

你会用到:

randomEnum(MyEnum.class);

我也更喜欢使用SecureRandom作为:

private static final SecureRandom random = new SecureRandom();

让函数从数组中随机选取一个值可能是最简单的。这是更通用的,并且调用起来很简单。

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

像这样叫:

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

在枚举上实现一个随机函数更容易。

public enum Via {
A, B;


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

然后你从类中调用它,像这样

public class Guardia{
private Via viaActiva;


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

同意stephen C &赫利俄斯。从Enum中获取随机元素的更好方法是:

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)];
}
}

一行

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

这里有一个使用shuffle和streams的版本

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

这可能是实现目标最简洁的方式。你所需要做的就是调用Letter.getRandom(),你会得到一个随机枚举字母。

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


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

我会用这个:

private static Random random = new Random();


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

简单的Kotlin解决方案

MyEnum.values().random()

random()是基本Kotlin中包含在Collection对象上的默认扩展函数。Kotlin文档链接

如果你想用扩展函数来简化它,试试这个:

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


// Then call
random<MyEnum>()

使它在枚举类上是静态的。确保在枚举文件中导入my.package.random

MyEnum.randomValue()


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

如果您需要从枚举的实例执行此操作,请尝试此扩展

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


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

我想这个单行返回方法足够有效,可以用于这样一个简单的工作:

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());
}
}

enum ShapeColor { 蓝色, 黄色的, 红色, 绿色, 白色 } < / p >

    Random random=new Random();
ShapeColor[] values=ShapeColor.values();
int size=values.length;
return values[random.nextInt(size)];
public static Letter randomLetter() {
return List.of(values()).get(Random.randomInt(List.of(values()).size()));


}