Python 列表推导式
在Python中,如何用列表推导式来实现下面这个Common Lisp代码的功能:
(loop for x = input then (if (evenp x)
(/ x 2)
(+1 (* 3 x)))
collect x
until (= x 1))
6 个回答
4
Laurence提到的这个黑科技:
你可以用一种列表推导式来实现,但结果会变得非常糟糕,简直是不可读的代码,真是太糟糕了。我只是把下面的内容当作好奇心的展示,并不是一个实际的解决方案。不要在你想要用的代码中这样做,只有在你想玩玩Python内部工作原理的时候才可以。
所以,有三种方法:
辅助列表 1
第一种:使用一个辅助列表,结果会放在这个辅助列表里。这个方法会把值添加到正在遍历的列表中,直到你达到想要停止的值。
A = [10]
print [None if A[-1] == 1
else A.append(A[-1]/2) if (A[-1]%2==0)
else A.append(3*A[-1]+1)
for i in A]
print A
结果:
[None, None, None, None, None, None, None]
[10, 5, 16, 8, 4, 2, 1]
辅助列表 2
第二种:同样使用辅助列表,但结果是列表推导式的输出。这个方法主要依赖于 list.append(...)
返回 None
,而 not None
被认为是 True
,而 True
在算术运算中被视为 1
。唉。
A=[10]
print [A[0]*(not A.append(A[0])) if len(A) == 1
else 1 if A[-1] == 2 else (A[-1]/2)*(not A.append(A[-1]/2)) if (A[-1]%2==0)
else (3*A[-1]+1)*(not A.append(3*A[-1]+1))
for i in A]
结果:
[10, 5, 16, 8, 4, 2, 1]
从内部引用列表推导式
第三种:不使用辅助列表,而是在构建列表推导式时引用它。这种方法有点脆弱,可能在所有环境下都不适用。如果不行,可以尝试单独运行这段代码:
from itertools import chain, takewhile
initialValue = 10
print [i if len(locals()['_[1]']) == 0
else (locals()['_[1]'][-1]/2) if (locals()['_[1]'][-1]%2==0)
else (3*locals()['_[1]'][-1]+1)
for i in takewhile(lambda x:x>1, chain([initialValue],locals()['_[1]']))]
结果:
[10, 5, 16, 8, 4, 2, 1]
所以,现在忘掉你读过的这些。这是黑暗、阴暗的Python。邪恶的Python。我们都知道Python并不邪恶。Python是可爱和友好的。所以你不能记得这些,因为这种东西是不存在的。很好很好。
9
我觉得你是在写“冰雹序列”,不过我可能错了,因为我对Lisp不太熟悉。
据我所知,你不能仅仅用列表推导来完成这个,因为每个元素都依赖于前一个元素。
我会这样做:
def hailstone(n):
yield n
while n!=1
if n%2 == 0: # even
n = n / 2
else: # odd
n = 3 * n + 1
yield n
list = [ x for x in hailstone(input) ]
当然,输入的内容会是你所提供的任何数据。
我的冰雹函数可能可以写得更简洁一些,但我的目标是让它更清晰。
10
列表推导式是一种用来从已有的序列中提取数据并进行某些操作或筛选的方法,最终生成一个新的列表。所以在这种情况下,使用列表推导式不太合适,因为你没有一个起始的序列。下面是一个使用while循环的例子:
numbers = []
x=input()
while x != 1:
numbers.append(x)
if x % 2 == 0: x /= 2
else: x = 3 * x + 1