[英]is it possible to convert this loop into a list comprehension in python
我有一小段code
,我想知道它是否可以用list comprehension
编写。 while loop
部分是我对浓缩感兴趣的部分。
>>> sum=33
>>> final_list=[]
>>> LastCoin=[0, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2,
1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1]
>>> while sum>0:
... final_list.append(LastCoin[sum])
... sum-=LastCoin[sum]
...
>>> print final_list
[1, 2, 5, 5, 5, 5, 5, 5]
>>>
您尝试使用列表理解有什么好的理由吗?
我个人看到很多人试图在不属于它们的地方楔入列表推导式,因为,您知道,'列表推导式更快 - 它们使用原生 C! 而你无聊的循环是在解释型 Python 中。 这并不总是正确的。
作为参考,如果我们将您简洁易读的原始解决方案与两个建议的答案进行比较,您可能会发现违反了您的假设:
In [5]: %%timeit
...: sum=33
...: while sum > 0:
...: final_list.append(LastCoin[sum])
...: sum -= LastCoin[sum]
...:
100000 loops, best of 3: 1.96 µs per loop
In [6]: %%timeit
...: sum=33
...: susu = [sum]
...: susu.extend(x for x in xrange(sum,-1,-1)
...: if x==(susu[-1]-LastCoin[susu[-1]])!=0)
...: fifi = [LastCoin[x] for x in susu]
...:
100000 loops, best of 3: 10.4 µs per loop
# 5x slower
In [10]: %timeit final_list = [LastCoin[reduce(lambda x, y: x - LastCoin[x], range(counter, i, -1))] for i in range(counter -1, 0, -1) if reduce(lambda x, y: x - LastCoin[x], range(counter, i, -1))]
10000 loops, best of 3: 128 µs per loop
# More than 60x slower!!
如果您试图为列表中的每个元素做一些事情,列表理解是一个不错的选择 - 过滤(测试每个元素的真/假)、翻译等,其中每个元素的操作都是分开的(理论上,可以经常被并行化)。 它不太擅长在循环期间进行处理和更改状态的循环,并且在您尝试时它们通常看起来很丑陋。 在这种特殊情况下,您在浏览列表时只查看 8 个项目,因为您正在手动计算要查看的索引。 在列表理解的情况下,您至少必须查看所有 33 个。
我不知道这是否是你的动机,但如果是,就让它作为一个循环。 毕竟 Python 循环并没有那么糟糕!
是的,这是可能的:
counter = 33 # your sum variable
LastCoin = [0, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2,
1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1]
final_list = [LastCoin[reduce(lambda x, y: x - LastCoin[x],
range(counter, i, -1))]
for i in range(counter -1, 0, -1)
if reduce(lambda x, y: x - LastCoin[x],
range(counter, i, -1))
]
print(final_list)
# [1, 2, 5, 5, 5, 5, 5, 5]
但是,这不是import this
的方式!
不试图使用列表理解。 改用递归。
与我以前的解决方案相比,更简单,执行时间除以 3。
LastCoin=[0, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2,
1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5,
1, 2, 1, 2, 5, 1, 2, 1]
def nekst(x,L,rec=None):
if rec is None: rec = []
rec.append(L[x])
if x-L[x]>0: nekst(x-L[x],L,rec)
return rec
print nekst(33,LastCoin)
结果
[1, 2, 5, 5, 5, 5, 5, 5]
注意:以下测试是使用没有行的递归函数完成的
if rec is None: rec = []
。
此行的存在会稍微增加 (+12%) 具有递归函数的解决方案的执行时间。
from time import clock
iterat = 10000
N = 100
LastCoin=[0, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2,
1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5,
1, 2, 1, 2, 5, 1, 2, 1]
counter = 33
te = clock()
for i in xrange(iterat):
final_list = [LastCoin[reduce(lambda x, y: x - LastCoin[x],
range(counter, i, -1))]
for i in range(counter -1, 0, -1)
if reduce(lambda x, y: x - LastCoin[x],
range(counter, i, -1))]
print clock()-te,'Omid Raha'
st=33
E1 = []
for n in xrange(N):
te = clock()
for i in xrange(iterat):
susu2 = [st]
susu2.extend(x for x in xrange(st,0,-1)
if x==(susu2[-1]-LastCoin[susu2[-1]]))
fifi2 = [LastCoin[x] for x in susu2]
del fifi2
E1.append(clock()-te)
t1 = min(E1)
print t1,'eyquem 1'
E2 = []
for n in xrange(N):
te = clock()
for i in xrange(iterat):
def nekst(x,L,rec):
rec.append(L[x])
if x-L[x]>0: nekst(x-L[x],L,rec)
return rec
fifi3 = nekst(st,LastCoin,[])
del fifi3,nekst
E2.append(clock()-te)
t2 = min(E2)
print t2,'eyquem 2, nekst redefined at each turn of the measurement loop'
def nekst(x,L,rec):
rec.append(L[x])
if x-L[x]>0: nekst(x-L[x],L,rec)
return rec
E22 = []
for n in xrange(N):
te = clock()
for i in xrange(iterat):
fifi3 = nekst(st,LastCoin,[])
del fifi3
E22.append(clock()-te)
t22 = min(E22)
print t22,'eyquem 2, nekst defined outside of the measurement loop'
W = []
for n in xrange(N):
te = clock()
for i in xrange(iterat):
y = 33
final_list=[]
while y>0:
final_list.append(LastCoin[y])
y-=LastCoin[y]
del final_list,y
W.append(clock()-te)
tw = min(W)
print tw,'while-loop == %.1f %% of %s' % (100*min(W)/min(E22),min(E22))
结果
4.10056836833 Omid Raha
0.29426393578 eyquem 1
0.114381576429 eyquem 2, nekst redefined at each turn of the measurement loop
0.107410299354 eyquem 2, nekst defined outside of the measurement loop
0.0820501882362 while-loop == 76.4 % of 0.107410299354
如果函数nekst()
的定义在时序循环之外执行,速度会快一些。
.
我不能做得更好:
sum=33
LastCoin=[0, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2,
1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5,
1, 2, 1, 2, 5, 1, 2, 1]
susu = [sum]
susu.extend(x for x in xrange(sum,0,-1)
if x==(susu[-1]-LastCoin[susu[-1]]))
fifi = [LastCoin[x] for x in susu]
print 'susu == %r\n'\
'fifi == %r\n'\
'wanted : %r' % (susu,fifi,[1, 2, 5, 5, 5, 5, 5, 5])
结果
susu == [33, 32, 30, 25, 20, 15, 10, 5]
fifi == [1, 2, 5, 5, 5, 5, 5, 5]
wanted : [1, 2, 5, 5, 5, 5, 5, 5]
.
x for x in xrange(sum,0,-1) if x==(susu[-1]-LastCoin[susu[-1]])
而不是原来的x for x in xrange(sum,-1,-1) if x==(susu[-1]-LastCoin[susu[-1]])!=0
我参加聚会可能有点晚了。 使用 python 3.9,我们可以使用海象运算符 (:=)
如果我们使用它,我们可以执行以下操作并将 while 语句减少到一行。
LastCoin=[0, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5, 1, 2,
1, 2, 5, 1, 2, 1, 2, 5, 1, 2, 1, 2, 5,
1, 2, 1, 2, 5, 1, 2, 1]
s = 33
final_list = [LastCoin[s]]
while (s:=s-LastCoin[s]) > 0: final_list.append(LastCoin[s])
print (final_list)
输出将是:
[1, 2, 5, 5, 5, 5, 5, 5]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.