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

Nic*_*ner 149 java random enums

如果我有这样的枚举:

public enum Letter {
    A,
    B,
    C,
    //...
}
Run Code Online (Sandbox Code Playgroud)

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

我可以做这样的事情

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

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

cle*_*tus 134

我唯一建议的是缓存结果,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));
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我真的没有看到将`values()`数组转换为不可修改的列表的重点."VALUES"对象已经被声明为"私有"而被封装.使它成为私有静态最终字母[] VALUES = ...`会更简单,更有效. (14认同)
  • 如果您认为它很有用,您可以创建一个实用程序类来执行此操作.类似RandomEnum <T的东西扩展了Enum>,接收类<T>的构造函数用于创建列表. (8认同)
  • private static final Letter [] VALUES ...没问题.它是私人的,所以它是不可改变的.您只需要公共randomLetter()方法,它显然返回单个值.斯蒂芬C是对的. (5认同)
  • Java中的数组是可变的,所以如果你有一个数组字段并在公共方法中返回它,调用者可以修改它并修改私有字段,因此你需要防御性地复制数组.如果你多次调用该方法可能会出现问题,所以你把它放在一个不可变的列表中,以避免不必要的防御性复制. (4认同)
  • @cletus:Enum.values() 将在每次调用时返回一个新数组,因此在其他地方传递/使用它之前无需包装它。 (2认同)

Eld*_*ell 111

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

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

您将使用哪个:

randomEnum(MyEnum.class);
Run Code Online (Sandbox Code Playgroud)

我也更喜欢使用SecureRandom:

private static final SecureRandom random = new SecureRandom();
Run Code Online (Sandbox Code Playgroud)


tra*_*god 42

结合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)];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:糟糕,我忘记了有界类型参数,<E extends Enum<E>>.


Moh*_*aie 28

单线

return Letter.values()[new Random().nextInt(Letter.values().length)];
Run Code Online (Sandbox Code Playgroud)

  • 应该是最受欢迎的答案! (5认同)
  • 简单又容易 (2认同)

Gib*_*olt 12

简单的 Kotlin 解决方案

MyEnum.values().random()
Run Code Online (Sandbox Code Playgroud)

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

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

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

// Then call
random<MyEnum>()
Run Code Online (Sandbox Code Playgroud)

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

MyEnum.randomValue()

// Add this to your enum class
companion object {
    fun randomValue(): MyEnum {
        return random()
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

// Then call
MyEnum.VALUE.random() // or myEnumVal.random() 
Run Code Online (Sandbox Code Playgroud)


Dee*_*pti 10

同意Stphen C&helios.从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)];
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)];
Run Code Online (Sandbox Code Playgroud)


Jos*_*son 6

使用函数从数组中选择随机值可能是最简单的。这是更通用的,并且可以直接调用。

<T> T randomValue(T[] values) {
    return values[mRandom.nextInt(values.length)];
}
Run Code Online (Sandbox Code Playgroud)

像这样调用:

MyEnum value = randomValue(MyEnum.values());
Run Code Online (Sandbox Code Playgroud)


小智 6

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

List<Direction> letters = Arrays.asList(Direction.values());
Collections.shuffle(letters);
return letters.stream().findFirst().get();
Run Code Online (Sandbox Code Playgroud)


Adi*_*dil 5

这可能是实现目标的最简洁的方法。您需要做的就是调用Letter.getRandom(),您将获得一个随机的枚举字母。

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

    public static Letter getRandom() {
        return values()[(int) (Math.random() * values().length)];
    }
}
Run Code Online (Sandbox Code Playgroud)