使用像https://www.npmjs.com/package/cartesian-product-generator这样的库,我可以生成一个笛卡尔积迭代器,当我有4个数组,每个长度为100,给出1亿个组合时,这是必要的,,这对于生成一个数组来说太占用内存了。
然而,我想随机化这1亿个组合,这样我就可以以随机的顺序迭代所有的组合,我怎样才能随机化迭代的顺序而不把所有的1亿个组合都带入内存呢?
使用像https://www.npmjs.com/package/cartesian-product-generator这样的库,我可以生成一个笛卡尔积迭代器,当我有4个数组,每个长度为100,给出1亿个组合时,这是必要的,,这对于生成一个数组来说太占用内存了。
然而,我想随机化这1亿个组合,这样我就可以以随机的顺序迭代所有的组合,我怎样才能随机化迭代的顺序而不把所有的1亿个组合都带入内存呢?
2条答案
按热度按时间0g0grzrc1#
你可以使用下面的技巧。
考虑从元素到数字的Map。
以彼得斯为例:
您可以将arr1Map到(0,1,2),将arr2Map到(0,1),将arr3Map到(0,1)。
因此,像201这样的3位数将编码为r-晚-高。
但您可以将Map转换为十进制数,它是3 * 2 *= 12个组合,因此您的十进制数将需要2位数或适合4位("1001")。
这样,你的12个组合就可以通过生成数字0 - 11并对这些数字进行 Shuffle 来 Shuffle 。生成一个0 - 11的随机数,并使用位数组标记每个已观察/测试的组合。
在一个普通的例子中,每个数组的大小都是10,你可以直接用这个数字作为你的值的键,最后一个数字表示最后一个数组的元素,第一个数字表示第一个数组的第一个数字,依此类推。
处理不同的数组大小和10以下和10以上的数字需要更多的关注,但它是简单的乘法/除法和模运算。
例如,给定大小为212、7和19的3个数组,则有212 * 7 * 19 = 28196种可能的组合。
生成sample = rnd(28196)并得到13936,然后取该值模19(% arr3.length()),即9,因此选择第3个数组索引9处的元素。
你用13936/19得到733,733%7等于5,所以这表示arr2的第5个元素。
733/7 = 104,104%212为104,因此您从arr1中选取第104个元素。此操作可重复且快速。在位数组中,将索引13936处的位标记为true(默认值:假)。
我不是用JS而是用Scala写了一个类似的算法,它非常快。
如果你碰巧搜索了几乎整个数组,当数组的99. 999%已经标记为"真"时,搜索会变得很慢,重复的随机数总是返回一个已经测试过的值。那么你可能最好按顺序访问元素或对看到的元素进行计数,只从size-count中生成一个随机数,然后迭代位数组,跳过所有看到的位。你甚至可以从策略1开始,当事情变慢时切换到第二个。
xqkwcwgp2#
你不能使用迭代器来随机化结果,因为你需要内存中的所有数组来随机化。
但是,您可以构建自己的随机笛卡尔积生成器:
更新1基于其他要求,以避免重复任何产品:
输出:(多个随机输出中的一个)
一个
this.seen
散列跟踪已经返回的随机值。散列基于数组的随机索引,例如相对较短。所有组合都用完后,返回
null
。请记住,在许多大的数组中运行这个函数会随着时间的推移而变慢,因为会有许多次重试,例如,对看到的项目的命中率会随着时间的推移而增加。