Java 概率枚举中的随机值
我有一个枚举,我想从中随机选择一个值,但不是真正的随机。我希望到目前为止,某些值不太可能被选中。这是我到目前为止所拥有的Java 概率枚举中的随机值,java,enums,Java,Enums,我有一个枚举,我想从中随机选择一个值,但不是真正的随机。我希望到目前为止,某些值不太可能被选中。这是我到目前为止所拥有的 private enum Type{ TYPE_A, TYPE_B, TYPE_C, TYPE_D, TYPE_E; private static final List<Type> VALUES = Collections.unmodifiableList(Arrays.asList(values()));
private enum Type{
TYPE_A, TYPE_B, TYPE_C, TYPE_D, TYPE_E;
private static final List<Type> 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));
}
}
是否有一种有效的方法为每个值分配概率
从中找到的代码这里有一个随机选择枚举值的通用方法。您可以根据建议调整概率。假设值的数量有限,您可以使用单独的数组float[]weights;每个值的权重值。这些值将介于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
}
}
有几种方法,其中一种与您的方法类似
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<Type> 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();
}
}
下面是另一种允许在运行时指定分发的替代方法 包括亚历克赛·斯维里多夫的建议。另外,当有很多选择时,随机方法可以结合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<Option, Integer> buckets = new EnumMap<Option, Integer>(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();
}
}
你可以从图书馆使用
我想你误解了。这个想法是——你把所有的重量加起来。现在想象一下最大值=计算值的标尺。现在,在这条规则上划掉每一个砝码,第一个砝码将根据我在答案0到10中的例子,第二个砝码是10到11,第三个砝码是11到16,依此类推。现在把你们的手指指向我们的尺子的任意位置,看看你们指的是哪一段。编辑后的答案。这就是我最后要做的。谢谢顺便说一句,如果在构造函数中预先计算类型的边界,您可以提高性能,但在五种类型上它不是实际的。当只有几个值可供选择时,此算法是标准算法。当有许多选项时,可以使用基于树的选择算法来加速算法。要执行此操作,请拆分[0,1]将区间划分为若干段,例如100。然后,对于每个区间,您确定样本是否恰好有一个可能的结果。如果有,请在树中用该值标记该叶。对于具有多个可能结果的任何段,您将构建另一个仅跨该段的树。根据r限制递归E关于概率的解决方案。我不理解主方法中所做的事情。似乎比@AlexeySviridov提出的方法复杂得多,我将其简化了一点。只需一些代码来练习随机看跌期权,看看分布情况如何。
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<Option, Integer> buckets = new EnumMap<Option, Integer>(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();
}
}
EnumeratedDistribution<Type> 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();