是否有带权重的随机 nextInt?
Is there random nextInt with weights?
我正在使用随机 class 生成 1 到 5 之间的随机数,例如 myrandom.nextInt(6),它工作正常,但是我想知道是否有办法给出一个增加权重的特定数字是出现的概率,假设我希望数字“4”有 %40 的概率而不是 %20 概率,而其他数字 1、2、3、5 平均共享 %60 概率的其余部分。有办法吗?
提前致谢。
您必须生成更大范围的数字(例如从 1 到 100)并使用范围 return 您真正想要的数字。例如:(在伪代码中)
r = randint(1..100)
if (r >= 1 && r <= 20) // 20% chance
return 1
else if (r >= 21 && r <= 60) // 40% chance
return 2
等等
我使用数组。例如
int[] arr = {4, 4, 4, 5, 5, 6};
int a = arr[random.nextInt(arr.length)];
要获得更动态的解决方案,请试试这个。权重不必加起来为任何特定值。
public static <T> T choice(Map<? extends T, Double> map) {
if (map == null || map.size() == 0)
throw new IllegalArgumentException();
double sum = 0;
for (double w : map.values()) {
if (Double.compare(w, 0) <= 0 || Double.isInfinite(w) || Double.isNaN(w))
throw new IllegalArgumentException();
sum += w;
}
double rand = sum * Math.random();
sum = 0;
T t = null;
for (Map.Entry<? extends T, Double> entry : map.entrySet()) {
t = entry.getKey();
if ((sum += entry.getValue()) >= rand)
return t;
}
return t;
}
您可以随时轻松地从地图中添加/删除/更改条目。下面是如何使用此方法的示例。
Map<Integer, Double> map = new HashMap<>();
map.put(1, 40.0);
map.put(2, 50.0);
map.put(3, 10.0);
for (int i = 0; i < 10; i++)
System.out.println(choice(map));
pbadcefp 的答案可能是最简单的。由于您在评论中声明您需要它 "dynamic",这里有另一种方法。请注意,权重基本上指定了数字在数组中出现的频率以供选择
public int weightedRandom( Random random, int max, Map<Integer, Integer> weights ) {
int totalWeight = max;
for( int weight : weights.values() ) {
totalWeight += weight - 1;
}
int choice = random.nextInt( totalWeight );
int current = 0;
for( int i = 0; i < max; i++ ) {
current += weights.containsKey( i ) ? weights.get( i ) : 1;
if( choice < current ) {
return i;
}
}
throw new IllegalStateException();
}
用法示例:
Map<Integer, Integer> weights = new HashMap<>();
weights.put( 1, 0 ); // make choosing '1' impossible
weights.put( 4, 3 ); // '4' appears 3 times rather than once
int result = weightedRandom( new Random(), 5, weights );
基本上,这相当于应用于数组的 pbadcefp 解决方案 { 0, 2, 3, 4, 4, 4 }
如果您想使用百分比,则必须对此进行调整。只需相应地计算权重即可。另外,我没有测试 cornercases,所以你可能想更广泛地测试一下。
这绝不是一个完整的解决方案,但比起完整的解决方案,我更愿意提供一些工作,因为您应该自己完成一些工作。
我还要郑重声明,恕我直言,这是过度设计的;但你想要这样的东西。
我正在使用随机 class 生成 1 到 5 之间的随机数,例如 myrandom.nextInt(6),它工作正常,但是我想知道是否有办法给出一个增加权重的特定数字是出现的概率,假设我希望数字“4”有 %40 的概率而不是 %20 概率,而其他数字 1、2、3、5 平均共享 %60 概率的其余部分。有办法吗?
提前致谢。
您必须生成更大范围的数字(例如从 1 到 100)并使用范围 return 您真正想要的数字。例如:(在伪代码中)
r = randint(1..100)
if (r >= 1 && r <= 20) // 20% chance
return 1
else if (r >= 21 && r <= 60) // 40% chance
return 2
等等
我使用数组。例如
int[] arr = {4, 4, 4, 5, 5, 6};
int a = arr[random.nextInt(arr.length)];
要获得更动态的解决方案,请试试这个。权重不必加起来为任何特定值。
public static <T> T choice(Map<? extends T, Double> map) {
if (map == null || map.size() == 0)
throw new IllegalArgumentException();
double sum = 0;
for (double w : map.values()) {
if (Double.compare(w, 0) <= 0 || Double.isInfinite(w) || Double.isNaN(w))
throw new IllegalArgumentException();
sum += w;
}
double rand = sum * Math.random();
sum = 0;
T t = null;
for (Map.Entry<? extends T, Double> entry : map.entrySet()) {
t = entry.getKey();
if ((sum += entry.getValue()) >= rand)
return t;
}
return t;
}
您可以随时轻松地从地图中添加/删除/更改条目。下面是如何使用此方法的示例。
Map<Integer, Double> map = new HashMap<>();
map.put(1, 40.0);
map.put(2, 50.0);
map.put(3, 10.0);
for (int i = 0; i < 10; i++)
System.out.println(choice(map));
pbadcefp 的答案可能是最简单的。由于您在评论中声明您需要它 "dynamic",这里有另一种方法。请注意,权重基本上指定了数字在数组中出现的频率以供选择
public int weightedRandom( Random random, int max, Map<Integer, Integer> weights ) {
int totalWeight = max;
for( int weight : weights.values() ) {
totalWeight += weight - 1;
}
int choice = random.nextInt( totalWeight );
int current = 0;
for( int i = 0; i < max; i++ ) {
current += weights.containsKey( i ) ? weights.get( i ) : 1;
if( choice < current ) {
return i;
}
}
throw new IllegalStateException();
}
用法示例:
Map<Integer, Integer> weights = new HashMap<>();
weights.put( 1, 0 ); // make choosing '1' impossible
weights.put( 4, 3 ); // '4' appears 3 times rather than once
int result = weightedRandom( new Random(), 5, weights );
基本上,这相当于应用于数组的 pbadcefp 解决方案 { 0, 2, 3, 4, 4, 4 }
如果您想使用百分比,则必须对此进行调整。只需相应地计算权重即可。另外,我没有测试 cornercases,所以你可能想更广泛地测试一下。
这绝不是一个完整的解决方案,但比起完整的解决方案,我更愿意提供一些工作,因为您应该自己完成一些工作。
我还要郑重声明,恕我直言,这是过度设计的;但你想要这样的东西。