Python中的列表推导与迭代之间的可变状态

时间:2017-12-13 22:23:22

标签: python python-2.7 list-comprehension

我有一些非常像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)]

3 个答案:

答案 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]

注意:这是一个坏主意。 (我之所以这样做只是因为user2357112说没办法)

答案 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]