我正在尝试展开一些嵌套循环,以牺牲内存为代价(可能)获得更好的性能。在我的场景中,我最终会得到一个包含大约 3 亿个元素(元组)的列表,我必须以(或多或少)随机顺序产生这些元素。
在这个数量级上,random.shuffle(some_list)
真的不再可行了。
下面的例子说明了这个问题。请注意,在 x86_64 Linux 和 CPython 3.6.4 上,它将占用大约 11 GByte 的内存。
def get_random_element():
some_long_list = list(range(0, 300000000))
for random_item in some_long_list:
yield random_item
到目前为止,我的想法是每次迭代简单地生成一个随机索引,并从列表中(无限期地)产生随机选择的元素。它可能会多次生成某些元素并完全跳过其他元素,这是一个值得考虑的权衡。
在合理的内存和 CPU 时间范围内,我还有哪些其他选项可以只生成列表中的每个元素一次?
最佳答案
这是 Fisher-Yates-Knuth 就地采样 ( https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle )
内存稳定~4Gb(是的,我用的是100000000)
# Fisher-Yates-Knuth sampling, in-place Durstenfeld version
import numpy as np
def swap(data, posA, posB):
if posA != posB:
data[posB], data[posA] = data[posA], data[posB]
def get_random_element(data, datalen):
pos = datalen
while pos > 0:
idx = np.random.randint(low=0, high=pos) # sample in the [0...pos) range
pos -= 1
swap(data, idx, pos)
yield data[pos]
length = 100000000
some_long_list = list(range(0, length))
gen = get_random_element(some_long_list, length)
for k in range(0, length):
print(next(gen))
更新
为了提高速度,您可能还想内联 swap()
关于python - 以(伪)随机顺序从大列表中高效地生成元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49188162/