python - 以(伪)随机顺序从大列表中高效地生成元素

标签 python python-3.x random generator

我正在尝试展开一些嵌套循环,以牺牲内存为代价(可能)获得更好的性能。在我的场景中,我最终会得到一个包含大约 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/

相关文章:

python - 通过win32com对Excel文件中的一行进行排序

jquery - 使用 Flask-Bootstrap 时在 jquery-ui 之前加载 jquery

python - QSqlQuery中isValid()的解释

python-3.x - 如何在python中检查蓝牙设备的ping

javascript - 在 for 循环中从数组中获取随机项,然后从数组中删除

python - 在numpy中生成随机数的函数之间的差异

c# - 在图形中生成明显不同的 RGB 颜色

python - 使用python将目录内容复制到目录中

python - 如何修复 "TypeError: int() argument must be a string, a bytes-like object or a number, not ' NoneType'"

django - 如何使用 get_blob_to_stream 从 azure-storage 下载数据