对于模糊不清感到非常抱歉,但我实际上并不知道我所做的事情的哪些部分效率低下。
我制作了一个程序,该程序采用正整数列表(例如*):
[1, 1, 3, 5, 16, 2, 4, 6, 6, 8, 9, 24, 200,]
*真实列表的长度最多可达2000,而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)
答案 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)