I have something which is an awful lot like a list comprehension in Python, except that it shares mutable state between iterations. Is there any way to do it with a list com
You could do this in a single line, using e.g. reduce
(or functools.reduce
in Python 3):
>>> 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]
But this is not only ugly, but also inefficient, as it will create a new list in each iteration. Or in a similar fashion to Stefan's approach, without creating intermediate lists:
>>> functools.reduce(lambda lst, _: lst.append(f(lst[-1])) or lst, range(1, n), [x])
[1, 18, 9, 22, 11]
Or, as already hinted in the other answer, you could use itertools.accumulate
, which is a lot better, but still a bit of a mis-use, as it actually expects a binary function, whereas here we use neither the second parameter, nor the actual iterable passed into the function, except for the very first value.
>>> list(itertools.accumulate([x] * n, lambda y, _: f(y)))
[1, 18, 9, 22, 11]
Is there any way to do it with a list comprehension?
What I'm looking for is something like this...
batch = [??? for _ in xrange(n)]
Sure, no problem:
>>> 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]
No. Deliberately no. Eventually they put in itertools.accumulate
, which is the closest thing to an Officially Recommended way to implement recurrence relations in a functional manner, but it doesn't exist on 2.7. You could copy the "roughly equivalent to" Python implementation from the docs if you want.