是否可以将此循环转换为python中的列表解析

时间:2014-01-24 00:12:35

标签: python list while-loop list-comprehension

我有一点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]
>>> 

4 个答案:

答案 0 :(得分: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循环并不是那么糟糕!

答案 1 :(得分:2)

是的,有可能:

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

答案 2 :(得分:1)

修改

更好的解决方案

不尝试使用列表理解。改为使用递归。
与我之前的解决方案相比,更简单,执行时间除以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

答案 3 :(得分: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]