Pick a random weighted element, with sample, no replacement
给定一个表示抢劫表中奖励的结构,其中a是奖励类型,2是整数加权,这意味着a被拉出的可能性是d的两倍。
1 2 3 4 5 6 7 8 |
如何生成用于显示目的的样本+获胜者?
我当前(伪)代码:
1 2 3 4 5 6 | list out; foreach(entry:map){ for(entry.value){ out.add(a) } } |
号
然后创建一个用于显示的示例。
1 2 3 4 5 | Collections.shuffle(out); List display = out.stream() .distinct() .limit(8) .collect(Collectors.toList()); |
有了这段代码,我能相信吗?如果我选择胜利者
1 | winner = display.get(0); |
。
我认识到,添加最后一个元素可能会使结果倾斜,因为在发生不同的调用之后,它将使选择权重较低的数字的可能性更大。
但是,选择流的第一个元素应该是值得信任的,对吗?因为它是以前选的。独特的有状态诱导效应吗?
我喜欢马丁的回答,但我也会根据他提出的性能问题,发布我自己的警告/备选方案。使用map可以实现与自己的非常相似的实现(我将使用hashmap,因为它是我最喜欢的)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | private final AtomicLong idxCounter = new AtomicLong(0); private final Map<Long, Item> dropTable = new HashMap<>(); public void addDrop(Item item, long relativeFrequency) { while (relativeFrequency-- > 0) { Long nextIdx = idxCounter.getAndIncrement(); dropTable.put(nextIdx, item); } } private static final Random rng = new Random(System.currentTimeMillis()); public Item getRandomDrop() { Long size = idxCounter.get(); // randomValue will be something in the interval [0, size), which // should cover the whole dropTable. // See http://stackoverflow.com/questions/2546078 for a fair // implementation of nextLong. Long randomValue = nextLong(rng, size); return dropTable.get(randomValue); } |
从哈希图中按键获取值非常快。您可以通过指定
只要没有其他东西在玩弄
看看随机通用抽样和适配比例选择。根据权重取一个样本的简单方法可以通过将每个元素表示为一个间隔来解释,其长度与其权重成比例。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
号
然后选择0到9的随机数
当然,这是一个有点惯用的解释,在实际的代码中,您只保留上界,因为下界只是前一个元素的上界。然后您将选择第一个元素,它在随机指针的上方有边界。
更新:从数学的角度来看,你最初的重复元素的方法是可以的(选择双倍权重的兴高采烈的概率是双倍的),但当权重很高时,这将是一个问题:
您的数据结构实现似乎有点奇怪。我会这样做:
1 2 3 4 5 6 7 8 |
然后,为了使事情更快(或允许一个非常大的抢劫表),我会有一个值,如
如果你不想走那么远,你可以在你的解决方案中得到一个0到8之间的随机整数,它仍然有效。
你坚持这个配方有什么原因吗?