制作字典的更高内存效率方式是什么?

3
非常抱歉因为表述不清而给您带来困扰,但实际上我不知道我的操作中哪一部分是低效的。
我制作了一个程序,可以处理正整数列表(例如*):
[1, 1, 3, 5, 16, 2, 4, 6, 6, 8, 9, 24, 200,]

*真实列表的长度可以长达2000个元素,元素的值在0到100,000之间(不包括100,000)。
并创建一个字典,其中每个数字与其索引(例如:(number,index))成为键,每个键的值是输入中可以被它整除的每个数字(及其索引)的列表。
因此,3的条目将是:(3,2):[(16, 4),(6, 7),(6, 8),(9, 10),(24, 11)] 我的代码如下:
num_dict = {}
sorted_list = sorted(beginning_list)

for a2, a in enumerate(sorted_list):
    num_dict[(a, a2)] = []

for x2, x in enumerate(sorted_list):
    for y2, y in enumerate(sorted_list[x2 + 1:]):
        if y % x == 0:
            pair = (y, y2 + x2 + 1)
            num_dict[(x, x2)].append(pair)

但是,当我运行这个脚本时,我遇到了一个 MemoryError 错误。

我知道这意味着我的内存不足,但在我所处的情况下,增加更多的内存或更新到64位版本的Python都不是一个选项。

我确定问题不是来自于列表排序或第一个 for 循环。一定是第二个 for 循环。 我只是为了上下文而包含其他行。

以上列表的完整输出将是(抱歉,字典就是这样不排序):

(200, 12): []
(6, 7): [(24, 11)]
(16, 10): []
(6, 6): [(6, 7), (24, 11)]
(5, 5): [(200, 12)]
(4, 4): [(8, 8), (16, 10), (24, 11), (200, 12)]
(9, 9): []
(8, 8): [(16, 10), (24, 11), (200, 12)]
(2, 2): [(4, 4), (6, 6), (6, 7), (8, 8), (16, 10), (24, 11), (200, 12)]
(24, 11): []
(1, 0): [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (6, 7), (8, 8), (9, 9), (16, 10), (24, 11), (200, 12)]
(1, 1): [(2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (6, 7), (8, 8), (9, 9), (16, 10), (24, 11), (200, 12)]
(3, 3): [(6, 6), (6, 7), (9, 9), (24, 11)]

有没有更好的方法来处理这个问题?

编辑:

然后将使用此字典:

ans_set = set()
for x in num_dict:
    for y in num_dict[x]:
        for z in num_dict[y]:
            ans_set.add((x[0], y[0], z[0]))
return len(ans_set)

找出所有唯一可能的三元组,其中第三个值可以被第二个值整除,而第二个值可以被第一个整除,这与it技术有关。如果您认为有更好的方法来完成整个过程,我很乐意重新做整个过程。最终编辑:通过重新评估我所需要的功能,我已经找到了计算三元组数量的最佳方法。这种方法实际上并不会找到三元组,只是计算它们的数量。
def foo(l):
    llen = len(l)
    total = 0
    cache = {}
    for i in range(llen):
        cache[i] = 0
    for x in range(llen):
        for y in range(x + 1, llen):
            if l[y] % l[x] == 0:
                cache[y] += 1
                total += cache[x]
    return total

这里是一个函数的版本,它在执行过程中解释了思路(由于打印的垃圾信息,对于巨大的列表不太好):

def bar(l):
    list_length = len(l)
    total_triples = 0
    cache = {}
    for i in range(list_length):
        cache[i] = 0
    for x in range(list_length):
        print("\n\nfor index[{}]: {}".format(x, l[x]))
        for y in range(x + 1, list_length):
            print("\n\ttry index[{}]: {}".format(y, l[y]))
            if l[y] % l[x] == 0:
                print("\n\t\t{} can be evenly diveded by {}".format(l[y], l[x]))
                cache[y] += 1
                total_triples += cache[x]
                print("\t\tcache[{0}] is now {1}".format(y, cache[y]))
                print("\t\tcount is now {}".format(total_triples))
                print("\t\t(+{} from cache[{}])".format(cache[x], x))
            else:
                print("\n\t\tfalse")
    print("\ntotal number of triples:", total_triples)

5
目前来看,这似乎是一个XY问题。您为什么需要这些数据以及您计划如何使用它们?如果不知道这些信息,很难建议更好的替代方案。 - Jack
3
考虑到解决方案的风格,我猜测这是一个编程问题,需要对数据集的任意部分执行某种基于范围的查询。这类问题通常可以使用动态规划原理来解决,而不是构建可能答案的巨大映射表。 - paddy
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Julien
2
在最坏的情况下,您将拥有4,000,000个整数项加上2000 x 2个整数键以及结构开销。这将仅使用几兆字节的内存。您有回溯吗? - Klaus D.
1
交叉参考 https://dev59.com/6Jvga4cB1Zd3GeqP2XUM ? - גלעד ברקן
显示剩余8条评论
2个回答

2

首先,你可以避免不必要的信息重复。

当你已经拥有这些信息时,为每个多重元组(数字和索引)存储完整的信息是低效的。

例如,你可以这样做:

(3, 2): [(16, 4), (6, 7), (6, 8), (9, 10), (24, 11)]

(16看起来是错误的,因为它不是3的倍数,所以我猜你想说的是15)你可以选择:

(3, 2): [15, 6, 9, 24]
(6, 7): ...

这样可以减少你的存储需求,因为你可以从列表中的6找到所有索引,通过搜索元组。当然,遍历列表需要额外的处理工作,但是与其使用速度快但不可用的解决方案,还不如使用速度较慢但可用的解决方案:-)


你甚至可以通过不存储倍数,而是使用%来运行元组列表,以查看是否有倍数,从而进一步减少存储。


当然,这完全取决于你的实际需求,最好说明你想要实现什么目标,而不是预先假定一个解决方案。


哎呀,是的,16 是一个错误。如果您查看我的编辑,您可能会看到为什么我需要值也具有它们的索引(值需要直接引用其他键)。 - Elliot Roberts
我已经编辑了一下,详细说明了我需要字典的原因。如果我的其他代码中有“%”,我认为这将成为一个O(N^3)问题。 - Elliot Roberts

2

在像 pair = (y, y2 + x2 + 1)num_dict[(x, x2)].append(pair) 这样的地方重新构建元组是不必要的,因为你可以早期构建一个规范的元组集合,然后只需在容器中放置引用。我在我的机器上创建了一个2000项测试,它可以工作。我使用的是Python 3.4 64位,内存相对较小,仅有3.5 GIG...

import random

# a test list that should generate longish lists
l = list(random.randint(0, 2000) for _ in range(2000))

# setup canonical index and sort ascending
sorted_index = sorted((v,i) for i,v in enumerate(l))

num_dict = {}
for idx, vi in enumerate(sorted_index):
    v = vi[0]
    num_dict[vi] = [vi2 for vi2 in sorted_index[idx+1:] if not vi2[0] % v]

for item in num_dict.items():
    print(item)

这将通过创建每个元组的单个实例来很好地节省内存。 - Raymond Hettinger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接