制作字典的内存效率更高的方法?

时间:2016-10-11 02:50:41

标签: python algorithm dictionary

对于模糊不清感到非常抱歉,但我实际上并不知道我所做的事情的哪些部分效率低下。

我制作了一个程序,该程序采用正整数列表(例如*):

[1, 1, 3, 5, 16, 2, 4, 6, 6, 8, 9, 24, 200,]

*真实列表的长度最多可达200​​0,而0到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

我知道这意味着我的内存不足,但在我遇到的情况下,添加更多ram或更新到64位版本的python不是一种选择。

我确信问题不是来自列表排序或第一个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)

找到所有唯一可能的三元组,其中第三个值可以均匀地除以第二个值,可以平均除以第一个值。

如果你认为你知道一个更好的方法来完成整个事情,我可以重做整个事情。

最终编辑

通过重新评估我需要它做什么,我找到了找到三元组数量的最佳方法。这种方法实际上并没有找到三元组,它只计算它们。

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)

2 个答案:

答案 0 :(得分:2)

好吧,你可以通过不必要地复制信息来启动

当您已经拥有该信息时,为每个倍数存储完整元组(数字和索引)效率很低。

例如,而不是:

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

16似乎有误,因为它不是 3的倍数所以我猜你是{{1}你可以改为选择:

15

这大大减少了你的存储需求,因为你可以从列表中的(3, 2): [15, 6, 9, 24] (6, 7): ... 开始,通过搜索元组找到它的所有索引。当然,这将是遍历列表的额外处理工作,但是可能更好的工作解决方案比更快的非工作解决方案: - )

您可以通过不存储倍数来减少存储空间,而是使用6运行元组列表以查看是否有倍数。

但是,当然,这完全取决于您的实际要求,哪些更好地说明您尝试实现的 intent 而不是预先假设解决方案

答案 1 :(得分:2)

您可以在pair = (y, y2 + x2 + 1)num_dict[(x, x2)].append(pair)之类的地方重建元组,这样您就可以在早期构建规范的元组集,然后将引用放在容器中。我拼凑了一个2000项测试我的机器工作。我有一个64位的python 3.4和一个相对适中的3.5 GIG RAM ......

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)