答案 0 :(得分:3)
我有两个建议。第一种是更改rand_enum
函数,使其返回Enum.t:
let rand_enum ht n =
BatRandom.init n;
let hte = BatHashtbl.enum ht
in Array.enum (BatRandom.shuffle hte)
这并不是完全不同的(它仍然计算所有20k的随机枚举),但更接近你原来想要的。
或者,您可以随时获取HashTbl的源代码并使用rand_enum函数重新编译它。然而,这也可能不会那么不同,因为HashTbl是作为一个数组实现的,如果你想避免重复错误,你可能最终会使用shuffle。
答案 1 :(得分:2)
下一个潜在元素的密度是多少? decide
功能的费用是多少?
您当前的所有解决方案都有O(n)成本。 Fisher-Yates是O(n)(尝试为Enums调整它没有多大意义,因为它无论如何都需要强制枚举),而Array.to_list alos是O(n)。
如果您的decide
函数足够快且密度足够低,我认为构建所有符合条件的元素的列表/数组可能更简单(在表的每个元素上调用decide
),然后随机选择其中一个。
如果密度足够高且费用decide
,我认为你的第一个想法是随机挑选密钥并保留已经遇到的密钥列表。您将能够选择遇到的第一个符合条件的元素(decide
次呼叫的最佳数量)。这种枚举序列的方式“最终”成本很高,当所有元素都已被选中时,但如果密度很高,则不会遇到这种情况。
如果你不知道,从“高密度”假设开始可能会很有趣,一旦你看到桌子的某个部分,就会改变主意,但仍然没有找到。
最后:如果你不需要在生成序列期间添加/删除元素,那么将哈希表转换为数组一次并将forall(保留另一个键 - >数组索引表放在某处)会很有趣,因为当索引是连续的时,所有这些问题都会更简单。
答案 2 :(得分:2)
您的实施)(第二和第三)太复杂了。我不喜欢mutable
,我不喜欢Enum
。将两者结合起来是最好的方法,可以通过不受控制的副作用来拍摄脚部。
我还认为你的特定问题太具体了,不能通过看起来像通用的“随机播放的东西而且就是它”来解决。试图找到这样一个独立于域的函数,它也能解决你的特定领域问题,这也许就是为什么你的连续实现在每次尝试时变得更加丑陋和复杂。
从Hashtable生成随机流很简单:BatHashtbl.enum |- BatRandom.shuffle |- BatArray.enum
。其余代码应该涉及decide
函数的使用。
答案 3 :(得分:0)
我怀疑Hashtbl暴露的界面有这样的功能。将所有值放入数组并通过Array.get a (Random.int (Array.length a))
进行查找的明显方法对我来说很好。