在python中将两个项目列表相加的最快方法

时间:2014-05-10 15:07:59

标签: python list numpy

我有一个奇怪的要求,我希望以最高的效率解决;我有两个列表list_1list_2,它们都是相同的长度,并且都只包含大于或等于0的整数。我想创建一个新的列表list_3,这样每个元素i是来自ilist_1的{​​{1}}位置元素的总和。在python中,这就足够了:

list_2

然而,有一个问题。对于每list_3 = [list_1[i] + list_2[i] for i in range(len(list_1))] i 0 <= i < len(list_1),如果位置i(即list_1[i])的项目为0,则list_1[i]和{{1}的总和} 也应为零

最有效的方法是什么?我必须在列表中执行此操作,其中包含323个元素,并且它需要用于游戏,因此它应该能够每秒轻松运行60次,同时允许在游戏中计算其他事物的大量额外时间。我想知道是否有任何花哨的方式可以做到这一点,但我不够精通numpy来确定。

编辑:

就简单地总结两个元素而言,一些常见的表达式是:

list_2[i]

编辑2:

我知道条件列表理解,但我想知道是否有比这更快的方法。

编辑3:

以下是给出方法的一些时间安排:

list_3 = [list_1[i] + list_2[i] for i in range(len(list_1))]
list_3 = [sum(t) for t in zip(list_1, list_2)]
list_3 = numpy.add(list_1, list_2)

还有什么更快的吗?

编辑4:

以下是我需要解释的内容:我正在制作视频游戏,需要系统不时检查键盘上某些键的状态。系统需要工作的方式是按下按键的时间越长,所述按键的计数器越高。一旦释放该键,计数器将重新设置为0.这需要对所有键执行,而不仅仅是少数几个键。根据{{​​1}},与其他计划相比,它目前是一个瓶颈。

以下是生成键盘中每个键状态的代码(它使用>>> import timeit >>> setup=''' import random list_1 = [random.randint(0, 323) for i in range(323)] list_2 = [random.randint(0, 323) for i in range(323)] ''' >>> timeit.timeit('list_3 = [list_1[i] + list_2[i] if list_2[i] else 0 for i in range(len(list_1))]', setup=setup, number=1) 6.005677381485953e-05 >>> timeit.timeit('list_3 = [x + y if y else 0 for x, y in zip(list_1, list_2)]', setup=setup, number=1) 3.604091037417601e-05 来获取键状态):

cProfile

6 个答案:

答案 0 :(得分:3)

  

按下一个键的时间越长,所述键的计数器越高

除非您的用户有300个手指,否则他们一次最多只能按十个键。您可以注册keydown和keyup事件;当键按下时,保存帧计数器或时间()/时钟()的返回值;当一个键启动或需要找到键的当前值时,减去差异。这会将循环次数减少到大约10而不是300.请注意,根据系统的不同,time()/ clock()可能是一个系统调用,可能很慢,因此使用帧计数器可能更为可取。

counter = 0
keys = {}
while True:
    for event in pygame.event.get() :
        if event.type == pygame.KEYDOWN :
            keys[event.key] = counter
        elif event.type == pygame.KEYUP :
            diff[event.key] = keys.pop(event.key) - counter
    counter += 1

但我非常怀疑这是你游戏的瓶颈。

答案 1 :(得分:1)

这在Python 3.x

中运行良好
list3 = [x+y if x and y else 0 for x, y in zip(list1, list2)]

或者,如果您使用的是Python 2.x:

import itertools as it
list3 = [x+y if x and y else 0 for x, y in it.izip(list1, list2)]

答案 2 :(得分:1)

设定:

import numpy as np
import random
list_1 = [random.randint(0, 323) for i in range(323)]
list_2 = [random.randint(0, 323) for i in range(323)]
array_1 = np.random.randint(0,323,323)
array_2 = np.random.randint(0,323,323)

原始时间:

%timeit list_3 = [list_1[i] + list_2[i] if list_2[i] else 0 for i in range(len(list_1))]
10000 loops, best of 3: 62.8 µs per loop

%timeit list_3 = [list_1[i] + list_2[i] if list_2[i] else 0 for i in range(len(list_1))]
10000 loops, best of 3: 62.3 µs per loop

Oscar Lopez的解决方案:

%timeit list3 = [x+y if x and y else 0 for x, y in zip(list_1, list_2)]
10000 loops, best of 3: 60.7 µs per loop

import itertools as it

%timeit list3 = [x+y if x and y else 0 for x, y in it.izip(list_1, list_2)]
10000 loops, best of 3: 50.5 µs per loop

Dawg的np.vectorize解决方案:

vector_func=np.vectorize(lambda e1, e2: e1+e2 if e1 and e2 else 0)

%timeit vector_func(array_1,array_2)
10000 loops, best of 3: 121 µs per loop

numpy解决方案:

%timeit out = array_1 + array_2; out[(array_1==0) & (array_2==0)] = 0
100000 loops, best of 3: 11.1 µs per loop

这里的问题是如果你选择使用list,那么numpy解决方案实际上是较慢的。

%%timeit
array_1 = np.array(list_1)
array_2 = np.array(list_2)
out = array_1 + array_2
out[(array_1==0) & (array_2==0)] = 0
10000 loops, best of 3: 84.8 µs per loop

numpy解决方案将是最快的,但你需要在一开始就使用numpy数组。

答案 3 :(得分:0)

您可以使用conditional expression

li1=[1,2,3,4,0,5,6]
li2=[1,2,3,0,5,6,7]

print [ li1[i] + li2[i]  if li1[i] and li2[i] else 0 for i in range(len(li1))]
# [2, 4, 6, 0, 0, 11, 13]

对于Numpy(您的问题被标记),您可以使用vectorize

>>> a1=np.array([1,2,3,4,0,5,6])
>>> a2=np.array([1,2,3,0,5,6,7])
>>> vector_func=np.vectorize(lambda e1, e2: e1+e2 if e1 and e2 else 0)
>>> vector_func(a1,a2)
array([ 2,  4,  6,  0,  0, 11, 13])

或者,如果您更喜欢lambda的函数:

>>> def vector(e1, e2):
...    if e1 and e2: return e1+e2
...    return 0
...
>>> vector_func=np.vectorize(vector)
>>> vector_func(a1,a2)
array([ 2,  4,  6,  0,  0, 11, 13])

使用您的计时代码,矢量化解决方案更快:

import timeit
import numpy as np
import random

a1=np.array([random.randint(0, 323) for i in range(323)])
a2=np.array([random.randint(0, 323) for i in range(323)])
vector_func=np.vectorize(lambda e1, e2: e1+e2 if e1 and e2 else 0)

n=10000

setup='''
from __main__ import a1, a2, vector_func
'''
print timeit.timeit('a3 = [a1[i] + a2[i] if a2[i] else 0 for i in range(len(a1))]', setup=setup, number=n)
print timeit.timeit('a3 = [x + y if y else 0 for x, y in zip(a1, a2)]', setup=setup, number=n)
print timeit.timeit('a3=vector_func(a1,a2)', setup=setup, number=n)

打印:

2.25640797615
1.97595286369
0.993543148041

Numpy比纯Python慢​​,但是如果你只有整数而没有其他理由使用numpy。

答案 4 :(得分:0)

list3 = [x + y for x, y in zip(list1, list2)]

答案 5 :(得分:0)

这是一个使用zip来说明常规和和条件和的示例:

>>> list_1 = [1,2,0,4,9]
>>> list_2 = [6,7,3,1,0]
>>> list_3 = [sum(v) for v in zip(list_1, list_2)] # regular sum
>>> list_3
[7, 9, 3, 5, 9]
>>> list_3 = [sum(v) if 0 not in v else 0 for v in zip(list_1, list_2)] # neither list_1[i] nor list_2[i] should be 0
>>> list_3
[7, 9, 0, 5, 0]
>>> list_3 = [sum(v) if v[0] != 0 else 0 for v in zip(list_1, list_2)] # list_1[i] should not be 0
>>> list_3
[7, 9, 0, 5, 9]

至于速度,任何理智的解决方案都会执行相同的操作 - 尽管为了节省内存,如果代码的其余部分允许,您可以考虑使用生成器表达式而不是列表。你应该选择最清晰的东西。