重み付けをしたランダム抽選ロジック作ったので共有
package org.chikishe.Util;
import java.util.ArrayList;
import java.util.Collection;
public class RandomUtil {
@SuppressWarnings("unchecked")
public static <T> T weightedRandom(Collection<T> resource,
Weight<T> delegate) throws Exception {
ArrayList<WeightCompare> weightedResource = new ArrayList<WeightCompare> ();
int totalWeight = 0;
for (T temp : resource) {
int weight = delegate.getWeight(temp);
if (weight <= 0)
continue;
totalWeight += weight;
weightedResource.add(new WeightCompare(temp, totalWeight));
}
if (totalWeight <= 0)
throw new Exception("No Resource");
int random = randomNext(1, totalWeight + 1);
int lower = -1;
int upper = weightedResource.size();
while (upper - lower > 1) {
int index = (lower + upper) / 2;
if (weightedResource.get(index).weight >= random) {
upper = index;
} else {
lower = index;
}
}
return (T) weightedResource.get(upper).obj;
}
public static int randomNext(int from, int to) {
return (int) (Math.random() * (to - from) + from);
}
public interface Weight<T> {
int getWeight(T temp);
}
private static class WeightCompare {
private Object obj;
private int weight;
public WeightCompare(Object obj, int weight) {
this.obj = obj;
this.weight = weight;
}
}
}
呼び出しは、次のようになります。
public String getTest4() {
ArrayList<TestMember> members = new ArrayList<TestMember>();
members.add(new TestMember(1, 50));
members.add(new TestMember(2, 80));
members.add(new TestMember(3, 130));
try {
TestMember member = RandomUtil.weightedRandom(members,
new Weight<TestMember>() {
public int getWeight(TestMember m) {
return m.weight;
}
});
return "" + member.id;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new WebApplicationException(500);
}
}
private class TestMember {
public int id;
public int weight;
public TestMember(int id, int weight) {
this.id = id;
this.weight = weight;
}
}
RandomUtil.weightedRandomはジェネリック型を受け取るようにしているので
第1引数のリストに指定した型を返します。
第2引数には重み付けを与えるメソッドの定義を渡しています。
サンプルの場合は、リストのTestMemberクラスのweightを重みとして取得しています。
ジェネリックの使い方がようやくわかってきた。
追記
2014/01/* Java 8でのラムダ式を使った使用方法はこちら
0 件のコメント:
コメントを投稿