我有一个奇怪的要求,我希望以最高的效率解决;我有两个列表list_1
和list_2
,它们都是相同的长度,并且都只包含大于或等于0的整数。我想创建一个新的列表list_3
,这样每个元素i
是来自i
和list_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
答案 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]
至于速度,任何理智的解决方案都会执行相同的操作 - 尽管为了节省内存,如果代码的其余部分允许,您可以考虑使用生成器表达式而不是列表。你应该选择最清晰的东西。