数组列表中的随机元素具有不同的机会

时间:2016-08-06 10:37:32

标签: java

如标题中所述,我想使用不同的“随机化因子”从列表中获取随机元素。背景如下:

  • 我有一个类列表,其中我不知道类的数量。
  • 此列表中的所有类都使用一种方法扩展了一个公共超类,该方法返回了在列表中选择它们的几率。

我可能有一个想法,比如添加课程出现的所有机会百分比,如果超过100%,则将每个百分比除以相对机会仍然相同,总百分比不超过100%。可能不是很清楚,如果不是我会解释一下。

3 个答案:

答案 0 :(得分:2)

假设您在列表中有3个对象,并且这些对象具有“百分比”(您应该称之为“权重”,因为它不是百分比)为4,7和9。

总和所有重量:20。

所以第一个元素应该在平均20次中被选出4次,第二个元素应该从20中选出7次等等。

因此,生成0到20之间的整数。如果结果在0到4之间,则选择第一个元素。如果结果在4到11之间,则选择第二个,如果结果在11到20之间,则选择最后一个。

其余的只是实施细节。

答案 1 :(得分:1)

只需总结数字,在[0, 1)中创建一个随机值,多次乘以和迭代整个列表从结果中减去数字,直到得到一个数字< 0:

List<MyClass> elements = ...
double sum = elements.stream().mapToDouble(MyClass::getChance).sum();
double rand = Math.random() * sum;
MyClass choice = null;
for (MyClass e : elements) {
    choice = e;
    rand -= e.getChance();
    if (rand < 0) {
        break;
    }
}

答案 2 :(得分:0)

如果您要进行一次(或几次)查找,那么answer by @fabian就是好的。

如果您要做很​​多事情,那么该解决方案执行的顺序搜索效率不高。

对于更有效的解决方案,您需要更直接的查找,因此您需要通过累积机会组织数据。这可以使用二进制搜索作为数组完成,也可以作为累积机会键入的NavigableMap来完成。

使用NavigableMapnull,您可以使用TreeMap查找所选对象:

  

返回与严格大于给定密钥的最小密钥关联的键 - 值映射,如果没有这样的密钥,则返回public class MyObj { private final String name; private final int weight; public MyObj(String name, int weight) { this.name = name; this.weight = weight; } public String getName() { return this.name; } public int getWeight() { return this.weight; } @Override public String toString() { return this.name; } public static void main(String[] args) { // Build list of objects List<MyObj> list = Arrays.asList( new MyObj("A", 2), new MyObj("B", 6), new MyObj("C", 12) ); // Build map keyed by cumulative weight NavigableMap<Integer, MyObj> weighedMap = new TreeMap<>(); int totalWeight = 0; for (MyObj obj : list) { totalWeight += obj.getWeight(); weighedMap.put(totalWeight, obj); } System.out.println(weighedMap); // Pick 20 objects randomly according to weight Random rnd = new Random(); for (int i = 0; i < 20; i++) { int pick = rnd.nextInt(totalWeight); MyObj obj = weighedMap.higherEntry(pick).getValue(); System.out.printf("%2d: %s%n", pick, obj); } } }

所以,这是示例代码:

{2=A, 8=B, 20=C}
14: C
10: C
 9: C
 5: B
11: C
 3: B
 1: A
 0: A
 1: A
 7: B
 4: B
11: C
17: C
15: C
 4: B
16: C
 9: C
17: C
19: C
 2: B

示例输出

float_of_int 8/. float_of_int 2;;