Java 数组列表中具有不同机会的随机元素
正如在标题中所说,我想使用不同的“随机化因子”从列表中获取一个随机元素。背景如下:Java 数组列表中具有不同机会的随机元素,java,Java,正如在标题中所说,我想使用不同的“随机化因子”从列表中获取一个随机元素。背景如下: 我有一个班级列表,其中我不知道班级的数量 此列表中的所有类都使用一个方法扩展了一个公共超类,该方法返回在列表中选择它们的概率百分比 我可能有一个想法,比如加上所有班级出现的机会百分比,如果超过100%,则除以每个百分比,使相对机会保持不变,但总百分比不超过100%。它可能不是很清楚,如果不是的话,我会再解释一下。假设列表中有3个对象,这些对象的“百分比”(你应该称之为“权重”,因为它不是百分比)为4、7和9
- 我有一个班级列表,其中我不知道班级的数量
- 此列表中的所有类都使用一个方法扩展了一个公共超类,该方法返回在列表中选择它们的概率百分比
我可能有一个想法,比如加上所有班级出现的机会百分比,如果超过100%,则除以每个百分比,使相对机会保持不变,但总百分比不超过100%。它可能不是很清楚,如果不是的话,我会再解释一下。假设列表中有3个对象,这些对象的“百分比”(你应该称之为“权重”,因为它不是百分比)为4、7和9 所有权重之和:20 因此,第一个元素应该平均从20次中选出4次,第二个元素应该从20次中选出7次,以此类推 因此,生成一个介于0和20之间的整数。如果结果介于0和4之间,请拾取第一个元素。如果结果介于4和11之间,则选择第二个,如果结果介于11和20之间,则选择最后一个
剩下的只是实现细节。假设列表中有3个对象,这些对象的“百分比”(您应该称之为“权重”,因为它不是百分比)为4、7和9 所有权重之和:20 因此,第一个元素应该平均从20次中选出4次,第二个元素应该从20次中选出7次,以此类推 因此,生成一个介于0和20之间的整数。如果结果介于0和4之间,请拾取第一个元素。如果结果介于4和11之间,则选择第二个,如果结果介于11和20之间,则选择最后一个
剩下的只是实现细节。只需将数字相加,在
[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;
}
}
列表元素=。。。
double sum=elements.stream().mapToDouble(MyClass::getChance).sum();
double rand=Math.random()*和;
MyClass choice=null;
对于(我的e类:元素){
选择=e;
rand-=e.getChance();
if(rand<0){
打破
}
}
只需将数字相加,在[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;
}
}
列表元素=。。。
double sum=elements.stream().mapToDouble(MyClass::getChance).sum();
double rand=Math.random()*和;
MyClass choice=null;
对于(我的e类:元素){
选择=e;
rand-=e.getChance();
if(rand<0){
打破
}
}
如果您只想进行一次(或几次)查找,那么这个方法很好
但是,如果您要经常这样做,那么该解决方案执行的顺序搜索是无效的
为了获得更有效的解决方案,您需要更直接的查找,因此您需要按累积机会组织数据。这可以通过使用二进制搜索的数组或按累积机会键入的键来完成
使用NavigableMap
,例如,然后可以使用查找选定对象:
返回与严格大于给定键的最小键关联的键值映射,如果没有此类键,则返回null
下面是示例代码:
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);
}
}
}
如果您只想进行一次(或几次)查找,那么这个方法很好 但是,如果您要经常这样做,那么该解决方案执行的顺序搜索是无效的 为了获得更有效的解决方案,您需要更直接的查找,因此您需要按累积机会组织数据。这可以通过使用二进制搜索的数组或按累积机会键入的键来完成 使用
NavigableMap
,例如,然后可以使用查找选定对象:
返回与严格大于给定键的最小键关联的键值映射,如果没有此类键,则返回null
下面是示例代码:
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);
}
}
}
就是这样!我不知道我怎么会忘记想到那样的东西,谢谢。就是这样!我不知道我怎么会忘记想到那样的东西,谢谢。解释得很好。但是@JB Nizet的答案更适合我的问题,因为我只需要用总权重初始化我的类,定义一个“阈值”对每个类的权重定义一个“阈值”,然后随机化。解释得很好。但是@JB Nizet的答案更适合我的问题,因为我只需要用总权重初始化我的类,为每个类定义一个权重“阈值”,然后随机化。