具有概率的枚举的随机值

我有一个枚举,我想随机选择一个值,但不是真正随机的。 我希望到目前为止,某些值不太可能被选中。 这是我到目前为止所拥有的……

private enum Type{ TYPE_A, TYPE_B, TYPE_C, TYPE_D, TYPE_E; private static final List VALUES = Collections.unmodifiableList(Arrays.asList(values())); private static final int SIZE = VALUES.size(); private static final Random RANDOM = new Random(); public static Type randomType() { return VALUES.get(RANDOM.nextInt(SIZE)); } } 

是否有一种有效的方法为每个值分配概率?

代码从这里找到

几种方法,其中之一,类似于你的方法

 private enum Type{ TYPE_A(10 /*10 - weight of this type*/), TYPE_B(1), TYPE_C(5), TYPE_D(20), TYPE_E(7); private int weight; private Type(int weight) { this.weight = weight; } private int getWeight() { return weight; } private static final List VALUES = Collections.unmodifiableList(Arrays.asList(values())); private int summWeigts() { int summ = 0; foreach(Type value: VALUES) summ += value.getWeight(); return summ; } private static final int SIZE = summWeigts(); private static final Random RANDOM = new Random(); public static Type randomType() { int randomNum = RANDOM.nextInt(SIZE); int currentWeightSumm = 0; for(Type currentValue: VALUES) { if (randomNum > currentWeightSumm && randomNum <= (currentWeightSumm + currentValue.getWeight()) { break; } currentWeightSumm += currentValue.getWeight(); } return currentValue.get(); } } 

这是一种随机选择enum值的通用方法 。 您可以按照此处的建议调整概率。

假设您具有有限数量的值,则可以为每个值设置单独的数组(float []权重;)。 这些值将介于0和1之间。当您选择随机值时,还会在其间生成另一​​个随机数,并且仅在第二个生成的数字低于该值的权重时才选择该值。

您可以通过提供自定义构造函数来创建包含关联数据的枚举,并使用构造函数为概率分配权重,然后

 public enum WeightedEnum { ONE(1), TWO(2), THREE(3); private WeightedEnum(int weight) { this.weight = weight; } public int getWeight() { return this.weight; } private final int weight; public static WeightedEnum randomType() { // select one based on random value and relative weight } } 
 import java.util.*; enum R { a(.1),b(.2),c(.3),d(.4); R(final double p) { this.p=p; } private static void init() { sums=new double[values().length+1]; sums[0]=0; for(int i=0;i bins=new EnumMap(R.class); for(R r:R.values()) bins.put(r,0); final int n=1000000; for(int i=0;i 

这是另一种允许在运行时指定分布的替代方法。

包括Alexey Sviridov的建议。 当有很多选项时,方法random()也可以包含来自Ted Dunning的建议。

  private enum Option { OPTION_1, OPTION_2, OPTION_3, OPTION_4; static private final Integer OPTION_COUNT = EnumSet.allOf(Option.class).size(); static private final EnumMap buckets = new EnumMap(Option.class); static private final Random random = new Random(); static private Integer total = 0; static void setDistribution(Short[] distribution) { if (distribution.length < OPTION_COUNT) { throw new ArrayIndexOutOfBoundsException("distribution too short"); } total = 0; Short dist; for (Option option : EnumSet.allOf(Option.class)) { dist = distribution[option.ordinal()]; total += (dist < 0) ? 0 : dist; buckets.put(option, total); } } static Option random() { Integer rnd = random.nextInt(total); for (Option option : EnumSet.allOf(Option.class)) { if (buckets.get(option) > rnd) { return option; } } throw new IndexOutOfBoundsException(); } } 

您可以使用Apache Commons Math库中的EnumeratedDistribution 。

 EnumeratedDistribution distribution = new EnumeratedDistribution<>( RandomGeneratorFactory.createRandomGenerator(new Random()), List.of( new Pair<>(Type.TYPE_A, 0.2), // get TYPE_A with probability 0.2 new Pair<>(Type.TYPE_B, 0.5), // get TYPE_B with probability 0.5 new Pair<>(Type.TYPE_C, 0.3) // get TYPE_C with probability 0.3 ) ); Type mySample = distribution.sample();