我需要在Python中执行此操作。 有一个给定的列表l,可能包含超过5000个整数元素。 数字之和有限,20000或可能很高。 输出应该是从列表中选取的2个数字的所有可能总和, 像,
l=[1,2,3,4,5,6,7,8,9]
output
1+1,1+2,1+3,1+4,1+5,1+6...........
2+2,2+3,2+4.......
.........
.......
2,3,4,5,6... like that
我正在使用此代码,暂时执行此操作, 但它很慢
l=listgen()
p=[]
for i in range(0,len(l)):
for j in range(i,len(l)):
k=l[i]+l[j]
if k not in p:
p.append(k)
p.sort
print(p)
listgen()
是生成输入列表的函数。
答案 0 :(得分:10)
一些老式的优化可能会让你获得比使用多个for循环的列表推导更容易理解的更快的代码:
def sums(lst, limit): # prevent global lookups by using a function
res = set() # set membership testing is much faster than lists
res_add = res.add # cache add method
for i, first in enumerate(lst): # get index and item at the same time
for second in lst[i:]: # one copy operation saves n index ops.
res_add(first + second) # prevent creation/lookup of extra local temporary
return sorted([x for x in res if x < limit])
print sums(listgen(), 20000)
作为额外的奖励,这个版本将与psyco,cython等进行精美优化。
<强>更新强> 将此与其他建议进行比较(将rangegen替换为范围(5000),我得到:
mine: 1.30 secs
WolframH: 2.65 secs
lazyr: 1.54 secs (estimate based on OPs timings -- I don't have Python 2.7 handy)
答案 1 :(得分:3)
编辑: Thebjorn说他有最有效的解决方案,而我自己的测试也同意,尽管我的性能有所改善。他的代码也更少依赖于python版本,似乎已经深思熟虑并在优化方面进行了解释。你应该接受他的回答(并给他赞成票)。
使用itertools.combinations_with_replacement
(在python 2.7中添加),并使p
成为set
。
def sums(lst, limit):
from itertools import combinations_with_replacement
p = set(x + y for x, y in combinations_with_replacement(listgen(), 2))
return sorted([x for x in p if x < limit])
由于这一行你的代码很慢:
if k not in p: # O(N) lookup time in lists vs average case O(1) in sets
如果您只是对代码进行了一些小的更改,以便p
为set
,则会产生巨大的差异:
L = listgen()
p = set()
for i in range(0, len(L)):
for j in range(i, len(L)):
p.add(L[i] + L[j])
print(sorted(p))
顺便说一下,你的例子中的这一行
p.sort
无效。你必须调用一个方法来实际执行它,如下所示:
p.sort()
答案 2 :(得分:2)
编辑:包含限制(不在OP的代码中)。
a = set(x + y for x in l for y in l)
print(sorted(x for x in a if x < limit))
这也降低了算法的复杂性(由于列表中的成员资格测试,你的算法可能是O(n ^ 4)。
答案 3 :(得分:1)
如果输入列表已排序,则可以在达到限制时跳出内循环。另外,将p
设为一组。
lst=listgen()
lst.sort()
p=set()
for i in range(0,len(lst)):
for j in range(i,len(lst)):
k=lst[i]+lst[j]
if k > limit:
break
p.add(k)
p = sorted(p)
print(p)
答案 4 :(得分:1)
你可以使用“NumPy”。 这绝对能为您提供所需的性能:
import numpy as np
data = np.arange(5000)
limit = 20000
result = np.zeros(0,dtype='i4')
for i in data:
result = np.concatenate((result,data[i]+data[i:]))
if len(result) >= limit: break
result = result[:limit]
修改强> 我刚刚意识到限制是在总和而不是在元素数量上。然后代码应为:
<强> EDIT2:强> 发现了进一步的逻辑错我更正的建议是:
for idx, x in np.ndenumerate(data):
result = np.concatenate((result,x+data[idx[0]:]))
if x + data[-1] >= limit: break
result = result[result <= limit]
答案 5 :(得分:0)
如果列表可以包含重复的元素,那么首先摆脱它们可能是明智的想法,例如通过将列表转换为集合。