我有一些非常像Python中的列表理解,除了它在迭代之间共享可变状态。有没有办法用列表理解来做到这一点?
def f(x):
""" 5-bit LFSR """
return (x >> 1) ^ (0x12*(x&1))
def batch(f, x, n):
result = [x]
for _ in xrange(1,n):
x = f(x)
result.append(x)
return result
batch(f, 1, 5)
返回[1, 18, 9, 22, 11]
。重要的是batch
函数,而不是f(x)
,这只是一个简单的例子来说明问题。
或者我可以使用生成器来实现:
def batch(f, x, n):
yield x
for _ in xrange(1,n):
x = f(x)
yield x
list(batch(f, 1, 5))
但它闻起来有点尴尬。我正在寻找的是这样的......
batch = [??? for _ in xrange(n)]
答案 0 :(得分:13)
有没有办法用列表理解来做到这一点?
我正在寻找的是这样的......
batch = [??? for _ in xrange(n)]
当然,没问题:
>>> x = 1
>>> n = 5
>>> [prev.append(f(prev[0])) or prev.pop(0) for prev in [[x]] for _ in xrange(n)]
[1, 18, 9, 22, 11]
答案 1 :(得分:4)
没有。故意没有。最终他们输入itertools.accumulate
,这是以官方推荐的方式以功能方式实现递归关系的最接近的东西,但它在2.7上并不存在。您可以复制"大致相当于"如果需要,可以使用docs的Python实现。
答案 2 :(得分:4)
你可以在一行中使用例如 reduce
(或Python 3中的functools.reduce
):
>>> f = lambda x: (x >> 1) ^ (0x12*(x&1))
>>> x, n = 1, 5
>>> functools.reduce(lambda lst, _: lst + [f(lst[-1])], range(1, n), [x])
[1, 18, 9, 22, 11]
但这不仅丑陋,而且效率低下,因为它会在每次迭代中创建一个新列表。或者以与Stefan的方法类似的方式,而不创建中间列表:
>>> functools.reduce(lambda lst, _: lst.append(f(lst[-1])) or lst, range(1, n), [x])
[1, 18, 9, 22, 11]
或者,正如在另一个答案中暗示的那样,你可以使用itertools.accumulate
,它好多了,但仍然有点误用,因为它实际上需要二进制函数,而在这里我们使用除了第一个值之外,第二个参数和实际的iterable都没有传递给函数。
>>> list(itertools.accumulate([x] * n, lambda y, _: f(y)))
[1, 18, 9, 22, 11]