【发布时间】:2023-03-03 11:55:01
【问题描述】:
背景:
我有一个包含 44906 个项目的列表:large = [1, 60, 17, ...]。我还有一台内存有限 (8GB) 的个人电脑,运行 Ubuntu 14.04.4 LTS。
目标:
我需要以节省内存的方式找到large 的所有成对组合,而不是事先用所有组合填充列表。
问题和我目前尝试的方法:
当我使用itertools.combinations(large, 2) 并尝试将其分配给一个列表时,我的内存会立即填满,并且我的性能非常缓慢。原因是成对组合的数量类似于n*(n-1)/2,其中n 是列表元素的数量。
n=44906 的组合数为44906*44905/2 = 1008251965。包含这么多条目的列表太大而无法存储在内存中。我希望能够设计一个函数,以便我可以插入一个数字 i 以在此列表中找到 ith 成对的数字组合,以及一种以某种方式动态计算此组合的方法,而无需参考到无法存储在内存中的 1008251965 元素列表。
我正在尝试做的一个例子:
假设我有一个数组small = [1,2,3,4,5]
在我有代码的配置中,itertools.combinations(small, 2) 将返回一个元组列表,如下所示:
[(1, 2), # 1st entry
(1, 3), # 2nd entry
(1, 4), # 3rd entry
(1, 5), # 4th entry
(2, 3), # 5th entry
(2, 4), # 6th entry
(2, 5), # 7th entry
(3, 4), # 8th entry
(3, 5), # 9th entry
(4, 5)] # 10th entry
像这样调用函数:`find_pair(10)' 会返回:
(4, 5)
,给出潜在数组中的第 10 个条目,但没有事先计算整个组合爆炸。
问题是,我需要能够进入组合的中间,而不是每次都从头开始,这似乎是迭代器所做的:
>>> from itertools import combinations
>>> it = combinations([1, 2, 3, 4, 5], 2)
>>> next(it)
(1, 2)
>>> next(it)
(1, 3)
>>> next(it)
(1, 4)
>>> next(it)
(1, 5)
因此,我希望能够通过一次调用检索第 10 次迭代返回的元组,而不是必须执行 next() 10 次才能到达第 10 个组合。
问题
是否还有其他以这种方式运行的组合函数旨在处理庞大的数据集?如果没有,是否有一种好方法可以实现这种行为的内存节省算法?
【问题讨论】:
-
二进制文件能满足您的需求吗?您可以使用
.seek( ) 命令对其进行索引。 -
我对你需要对你的组合做什么感到有点困惑。您的标题表明您想要迭代它们,从
itertools.combinations返回的迭代器似乎很理想(只是不要把它变成一个列表!)。但是,您的问题主体似乎需要以某种不清楚的方式随机访问组合。如果要迭代,则不需要随机访问。如果您确实需要随机访问,您可能会想出一种方法将您的组合索引转换为原始列表中的一对索引。 -
这里肯定发生了 XY 问题。你到底想做什么?
-
当然——尽管我发布的答案更快并且使用更少的内存。 /// 使用 itertools 生成器并将对直接写入文件;使用二进制格式,以便每个整数占用相同数量的空间(每个 4 个字节,每对 8 个字节)。以 pair_file 的形式打开您的二进制文件。当你想从集合中配对 N 时,执行 pair_file.seek(8*N) 然后从该点读取两个整数。
-
@jackskis,这完全没问题。基本整数远大于此(32 或 64 位)。
标签: python list combinations combinatorics large-data