编辑: 请参阅最后的编辑,以获取更优雅的解决方案。我会留在这。
您可以使用
NavigableMap存储映射到其百分比的这些方法。
NavigableMap<Double, Runnable> runnables = new TreeMap<>();runnables.put(0.3, this::30PercentMethod);runnables.put(1.0, this::70PercentMethod);public static void runRandomly(Map<Double, Runnable> runnables) { double percentage = Math.random(); for (Map.Entry<Double, Runnable> entry : runnables){ if (entry.getKey() < percentage) { entry.getValue().run(); return; // make sure you only call one method } } throw new RuntimeException("map not filled properly for " + percentage);}// or, because I'm still practicing streams by using them for everythingpublic static void runRandomly(Map<Double, Runnable> runnables) { double percentage = Math.random(); runnables.entrySet().stream() .filter(e -> e.getKey() < percentage) .findFirst().orElseThrow(() -> new RuntimeException("map not filled properly for " + percentage)) .run();}将
NavigableMap被 分类
(例如
HashMap没有给出该项目的担保)的按键,让您获得通过他们的百分比排序的条目。这是相关的,因为如果您有两项 (3,r1) ,
(7,r2) ,它们将产生以下条目:
r1 = 0.3并且
r2 = 1.0需要按此顺序进行评估(例如,如果按相反的顺序进行评估,则结果将 永远
是
r2)。
至于拆分,它应该是这样的:使用类似Tuple的类
static class Pair<X, Y>{ public Pair(X f, Y s) { first = f; second = s; } public final X first; public final Y second;}您可以像这样创建地图
// the parameter contains the (1,m1), (1,m2), (3,m3) pairsprivate static Map<Double,Runnable> splitToPercentageMap(Collection<Pair<Integer,Runnable>> runnables){ // this adds all Runnables to lists of same int value, // overall those lists are sorted by that int (so least probable first) double total = 0; Map<Integer,List<Runnable>> byNumber = new TreeMap<>(); for (Pair<Integer,Runnable> e : runnables) { total += e.first; List<Runnable> list = byNumber.getOrDefault(e.first, new ArrayList<>()); list.add(e.second); byNumber.put(e.first, list); } Map<Double,Runnable> targetList = new TreeMap<>(); double current = 0; for (Map.Entry<Integer,List<Runnable>> e : byNumber.entrySet()) { for (Runnable r : e.getValue()) { double percentage = (double) e.getKey() / total; current += percentage; targetList.put(current, r); } } return targetList;}所有这些都添加到一个类中
class RandomRunner { private List<Integer, Runnable> runnables = new ArrayList<>(); public void add(int value, Runnable toRun) { runnables.add(new Pair<>(value, toRun)); } public void remove(Runnable toRemove) { for (Iterator<Pair<Integer, Runnable>> r = runnables.iterator(); r.hasNext(); ) { if (toRemove == r.next().second) { r.remove(); break; } } } public void runRandomly() { // split list, use pre from above }}编辑:
实际上,以上就是如果您有一个想法陷在头脑中,并且没有正确地质疑它,您会得到什么。保留
RandomRunner类接口,这要容易得多:
class RandomRunner { List<Runnable> runnables = new ArrayList<>(); public void add(int value, Runnable toRun) { // add the methods as often as their weight indicates. // this should be fine for smaller numbers; // if you get lists with millions of entries, optimize for (int i = 0; i < value; i++) { runnables.add(toRun); } } public void remove(Runnable r) { Iterator<Runnable> myRunnables = runnables.iterator(); while (myRunnables.hasNext()) { if (myRunnables.next() == r) { myRunnables.remove(); } } public void runRandomly() { if (runnables.isEmpty()) return; // roll n-sided die int runIndex = ThreadLocalRandom.current().nextInt(0, runnables.size()); runnables.get(runIndex).run(); }}


