实际场景中,经常要从多个选项中随机选择一个,不过,不同选项经常有不同的权重。
/**
* Created by xc on 2019/11/23
* 带权重的随机选择
*/
public class Test {
public static void main(String[] args) {
Pair[] options = new Pair[]{new Pair("first", 3.3), new Pair("second", 3.3), new Pair("third", 3.3)};
WeightRandom rnd = new WeightRandom(options);
for (int i = 0; i < 10; i++) {
System.out.print(rnd.nextItem() + " ");
}
}
}
/**
* Created by xc on 2019/11/25
* 表示选项和权重的类Pair
*/
public class Pair {
Object item;
double weight;
public Pair(Object item, double weight) {
this.item = item;
this.weight = weight;
}
public Object getItem() {
return item;
}
public double getWeight() {
return weight;
}
}
/**
* Created by xc on 2019/11/25
* 代码清单7-9 带权重的选择WeightRandom
*/
public class WeightRandom {
private Pair[] options;
private double[] cumulativeProbabilities;
private Random rnd;
public WeightRandom(Pair[] options) {
this.options = options;
this.rnd = new Random();
prepare();
}
/**
* prepare()方法计算每个选项的累计概率,保存在数组cumulativeProbabilities中
*/
private void prepare() {
int weights = 0;
for (Pair pair : options) {
weights += pair.getWeight();
}
cumulativeProbabilities = new double[options.length];
int sum = 0;
for (int i = 0; i < options.length; i++) {
sum += options[i].getWeight();
cumulativeProbabilities[i] = sum / (double) weights;
}
}
/**
* nextItem()方法根据权重随机选择一个,具体就是,首先生成一个0~1的数,
* 然后使用二分查找,如果没找到,返回结果是-(插入点)-1,所以-index-1就是插入点,插入点的位置就对应选项的索引。
* @return
*/
public Object nextItem() {
double randomValue = rnd.nextDouble();
int index = Arrays.binarySearch(cumulativeProbabilities, randomValue);
if (index < 0) {
index = -index - 1;
}
return options[index].getItem();
}
}