2013-04-18 66 views
8

我目前正在通过项目欧拉的问题,到目前为止我已经想出了这个问题的代码。有没有办法避免这种内存错误?

from itertools import combinations 
import time 

def findanums(n): 
    l = [] 
    for i in range(1, n + 1): 
     s = [] 
     for j in range(1, i): 
      if i % j == 0: 
       s.append(j) 
     if sum(s) > i: 
      l.append(i) 
    return l 

start = time.time() #start time 

limit = 28123 

anums = findanums(limit + 1) #abundant numbers (1..limit) 
print "done finding abundants", time.time() - start 

pairs = combinations(anums, 2) 
print "done finding combinations", time.time() - start 

sums = map(lambda x: x[0]+x[1], pairs) 
print "done finding all possible sums", time.time() - start 

print "start main loop" 
answer = 0 
for i in range(1,limit+1): 
    if i not in sums: 
     answer += i 
print "ANSWER:",answer 

当我运行这个我碰到一个MemoryError

回溯:

File "test.py", line 20, in <module> 
    sums = map(lambda x: x[0]+x[1], pairs) 

我试图阻止它从什么我已经能够从谷歌,但无济于事得到禁止垃圾收集。我以错误的方式接近这个吗?在我的脑海里,这感觉就像是最自然的做法,而且我现在处于亏损状态。

SIDE注意:我使用的是PyPy 2.0 Beta2(Python 2.7.4),因为它比我用过的其他Python实现快得多,而且Scipy/Numpy在我头上,因为我仍然只是开始编程,我没有工程或强大的数学背景。

+0

你得到了多少内存?系统是64位的? – Ofiris

+0

64位,8 GB的内存,虽然PyPy是32位的,如果这也有所改变。 –

+2

你似乎有某个地方的错误。如果在'findanums'运行后'打印len(anums)',它会给出'28123',这意味着从1到28123的_every_数字是一个非常丰富的数字。我不认为这是正确的。 – Kevin

回答

4

正如凯文在评论中提到的,你的算法可能是错误的,但无论如何你的代码没有被优化。

当使用非常大名单,这是通常使用generators,有一个著名的,伟大的答案#1解释yieldgenerator的概念 - What does the "yield" keyword do in Python?

的问题是,你的pairs = combinations(anums, 2)不产生generator ,但会产生一个消耗更多内存的大对象。

我改变你的代码有这个功能,因为你遍历集合只有一次,你可以偷懒评估值:

def generator_sol(anums1, s): 
     for comb in itertools.combinations(anums1, s): 
     yield comb 

的现在,而不是pairs = combinations(anums, 2)产生一个大对象。 用途:

pairs = generator_sol(anums, 2) 

然后,而不是使用lambda我会用另一种generator:在xrange这是更适合

sums_sol = (x[0]+x[1] for x in pairs) 

另一个技巧,你更好看,它好好尝试生成一个列表但是xrange object在许多情况下更高效(比如这里)。

+0

现在只是吐出一个错误的答案。你已经给了我很多东西来阅读和学习,所以我感谢你。发电机确实解决了我的记忆问题! –

+2

与欧拉计划祝你好运。 – Ofiris

+2

范围不会在pypy中产生一个列表 – fijal

1

问题是anums很大 - 大约有28000个元素。所以配对必须是28000 * 28000 * 8字节= 6GB。如果您使用numpy的,你可以投anums作为numpy.int16阵列,在这种情况下,结果对将1.5GB - 更易于管理:

import numpy as np 
#cast 
anums = np.array([anums],dtype=np.int16) 
#compute the sum of all the pairs via outer product 
pairs = (anums + anums.T).ravel() 
+1

正如我在我的文章中所说的,我仍然很绿,而且numpy的魔力仍然没有掌握,因为我仍然在学习普通的Python库。但是,我很欣赏这个答案,因为它让我尝到了一旦我学会了足够的使用numpy/scipy后能够做的事情! –

2

让我建议你使用generators。尝试改变这一点:

sums = map(lambda x: x[0]+x[1], pairs) 

sums = (a+b for (a,b) in pairs) 

Ofiris解决方案也确定,但暗示itertools.combinations返回一个列表,当它是错的。如果你打算继续解决项目欧勒问题,请看itertools documentation

+1

好评,谢谢,修正。 – Ofiris

+0

你是什么意思的'组合'返回一个列表,当它是错误的? –

+1

我说组合返回一个“列表”,它不正确,无论如何修复它。 – Ofiris

相关问题