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

时间:2009-12-29 00:54:29

标签: java random enums

如果我有这样的枚举:

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

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

我可以做这样的事情

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

但是有更好的方法吗?我觉得这是以前已经解决的问题。

14 个答案:

答案 0 :(得分:125)

我唯一建议的是缓存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));
  }
}

答案 1 :(得分:98)

您需要的所有随机枚举都需要一种方法:

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

答案 2 :(得分:41)

结合cletushelios的建议,

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>>

答案 3 :(得分:24)

单行

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

答案 4 :(得分:10)

同意Stphen C&amp;赫利俄斯。从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)];
  }
}

答案 5 :(得分:8)

简单的Kotlin解决方案

MyEnum.values().random()

random()Collection对象上基础Kotlin中包含的默认扩展功能。 Kotlin Documentation Link

如果您想使用扩展功能对其进行简化,请尝试以下操作:

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

答案 6 :(得分:4)

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

答案 7 :(得分:4)

这可能是实现目标的最简洁方式。您只需拨打Letter.getRandom()即可获得随机枚举字母。

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

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

答案 8 :(得分:3)

如果你这样做进行测试,可以使用Quickcheckthis is a Java port I've been working on)。

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的优势在于您可以基于specification定义测试,其中普通TDD适用于场景。

答案 9 :(得分:3)

最简单的方法是从数组中选择一个随机值。这是更通用的,并且可以直接调用。

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

这样打电话:

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

答案 10 :(得分:3)

这是一个使用shuffle和流的版本

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

答案 11 :(得分:2)

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

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

答案 12 :(得分:2)

我会用这个:

private static Random random = new Random();

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

答案 13 :(得分:1)

我猜想这种单行返回方法足够有效,可以用于如此简单的工作:

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