使用反射实现了一个通用的random by weight,只要被随机的结构中带有getWeight函数即可
public static <T extends Object>
T getRandomObjByWeight(List<T> objs, Class<?> clazz) {
try {
Method getWeightFunc = clazz.getMethod("getWeight");
Double totalWeight = 0.0;
for(Object obj : objs) {
Integer weight = (Integer)getWeightFunc.invoke(obj);
totalWeight += Double.valueOf(weight);
}
double random = Math.random() * totalWeight;
for(T obj : objs) {
Integer weight = (Integer)getWeightFunc.invoke(obj);
random -= Double.valueOf(weight);
if (random <= 0.0) {
return obj;
}
}
} catch (Exception e) {
LogUtil.LOG_BASE.error("getRandomObjByWeight异常", e.getMessage(), e);
}
return null;
}
测试代码
public class Item {
private Integer id;
private Integer weight;
public Item(Integer id, Integer weight) {
this.id = id;
this.weight = weight;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
}
public static void main(String[] args) {
List<Item> items = new ArrayList<>();
items.add(new Item(1, 50));
items.add(new Item(2, 50));
items.add(new Item(3, 50));
Map<Integer, Integer> counts = new HashMap<>();
for (int i = 0; i < 1000; ++i) {
Item item = GameUtil.getRandomObjByWeight(items, Item.class);
Integer count = counts.get(item.id);
if (count == null) {
counts.put(item.id, 1);
} else {
counts.put(item.id, count+1);
}
}
Integer total = 0;
for (Map.Entry<Integer, Integer> pair : counts.entrySet()) {
System.out.println("id=" + pair.getKey() + " count=" + pair.getValue());
total += pair.getValue();
}
System.out.println("total=" + total);
}