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

发布于 2024-08-16 02:50:32 字数 357 浏览 3 评论 0 原文

如果我有一个像这样的枚举:

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

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

我可以做这样的事情

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

红ご颜醉 2024-08-23 02:50:32

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

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));
  }
}
锦欢 2024-08-23 02:50:32

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

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

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();
梦幻的心爱 2024-08-23 02:50:32

单线

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

Single line

return Letter.values()[new Random().nextInt(Letter.values().length)];
慈悲佛祖 2024-08-23 02:50:32

结合 cletus 的建议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)];
        }
    }
}

编辑:哎呀,我忘记了有界类型参数,>

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

贪恋 2024-08-23 02:50:32

简单的 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() 

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() 
无畏 2024-08-23 02:50:32
Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)];
Letter lettre = Letter.values()[(int)(Math.random()*Letter.values().length)];
离笑几人歌 2024-08-23 02:50:32

同意 Stphen C 和 Stphen 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)];
  }
}

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)];
  }
}
墨落成白 2024-08-23 02:50:32

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

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

像这样调用:

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

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());
澜川若宁 2024-08-23 02:50:32

这是使用随机播放和流的版本

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

Here a version that uses shuffle and streams

List<Direction> letters = Arrays.asList(Direction.values());
Collections.shuffle(letters);
return letters.stream().findFirst().get();
清泪尽 2024-08-23 02:50:32

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

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

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

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)];
    }
}
那伤。 2024-08-23 02:50:32

如果您这样做是为了测试,您可以使用 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 适用于场景。

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.

南薇 2024-08-23 02:50:32

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

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

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());
    }
}
春夜浅 2024-08-23 02:50:32

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

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

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();
}
安稳善良 2024-08-23 02:50:32

我会用这个:

private static Random random = new Random();

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

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)];
}
行雁书 2024-08-23 02:50:32

枚举形状颜色{
蓝色的,
黄色的,
红色的,
绿色的,
白色的,
}

    Random random=new Random();
    ShapeColor[] values=ShapeColor.values();
    int size=values.length;
    return values[random.nextInt(size)];

enum ShapeColor {
Blue,
Yellow,
Red,
Green,
White,
}

    Random random=new Random();
    ShapeColor[] values=ShapeColor.values();
    int size=values.length;
    return values[random.nextInt(size)];
望笑 2024-08-23 02:50:32
public static Letter randomLetter() {
    return List.of(values()).get(Random.randomInt(List.of(values()).size()));

}
public static Letter randomLetter() {
    return List.of(values()).get(Random.randomInt(List.of(values()).size()));

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文