2

以下 Common Lisp 代码在 python 中的等效列表理解是什么:

(loop for x = input then (if (evenp x)
                             (/ x 2)
                             (+1 (* 3 x)))
      collect x
      until (= x 1))
4

6 回答 6

10

列表推导式用于获取现有序列并对其执行某些功能和/或过滤,从而产生一个新列表。因此,在这种情况下,列表推导是不合适的,因为您没有起始序列。带有 while 循环的示例:

numbers = []
x=input()
while x != 1:
  numbers.append(x)
  if x % 2 == 0: x /= 2
  else: x = 3 * x + 1
于 2009-07-13T23:24:13.917 回答
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) ]

当然,输入将保留您的输入。

我的冰雹功能可能更简洁。我的目标是清晰。

于 2009-07-13T23:21:24.580 回答
4

劳伦斯提到的黑客:

您可以在一个列表理解中做到这一点,它最终会成为 AWFUL python。不可读的蟒蛇。可怕的蟒蛇。我只是出于好奇而提出以下内容,而不是作为实际答案。不要在你真正想要使用的代码中这样做,只有当你想玩一下 python 的内部工作时。

所以,3种方法:


帮助清单 1

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

2:使用帮助列表,但结果是列表理解的输出。这主要依赖于为算术目的list.append(...)返回Nonenot None评估TrueTrue考虑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]

从内部引用列表理解

3:不使用帮助列表,而是在构建列表时引用它。这有点脆弱,可能不适用于所有环境。如果它不起作用,请尝试自行运行代码:

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 很可爱。所以你不可能读过这个,因为这种东西不可能存在。好好。

于 2009-07-14T15:55:53.677 回答
4

Python 没有内置这种控制结构,但您可以将其概括为如下函数:

def unfold(evolve, initial, until):
    state = initial
    yield state
    while not until(state):
        state = evolve(state)
        yield state

在此之后,您的表达式可以写成:

def is_even(n): return not n % 2
unfold(lambda x: x/2 if is_even(x) else 3*x + 1,
       initial=input, until=lambda x: x == 1)

但是 Pythonic 的方法是使用生成器函数:

def produce(x):
    yield x
    while x != 1:
        x = x / 2 if is_even(x) else 3*x + 1
        yield x
于 2009-07-14T05:51:10.773 回答
3

正如 Kiv 所说,列表推导需要一个已知的序列来迭代。

话虽如此,如果您有一个序列并且专注于使用列表推导,您的解决方案可能包括以下内容:

[not (x % 2) and (x / 2) or (3 * x + 1) for x in sequence]

迈克库珀的回答是一个更好的解决方案,因为它都保留了x != 1终止,而且这一行读起来不干净。

于 2009-07-13T23:45:36.713 回答
0

1

我发现了一个真正奇妙的证明,这个空白太窄而无法包含。

不过说真的,我不相信你可以用 Python 列表推导来做到这一点。它们与 map 和 filter 具有基本相同的功能,因此您无法在不求助于骇客的情况下突破或查看以前的值。

于 2009-07-13T23:21:04.563 回答