Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List Accumulation with Append

Tags:

python

list

I want to generate or return an append-accumulated list from a given list (or iterator). For a list like [1, 2, 3, 4], I would like to get, [1], [1, 2], [1, 2, 3] and [1, 2, 3, 4]. Like so:

>>> def my_accumulate(iterable):
...     grow = []
...     for each in iterable:
...         grow.append(each)
...         yield grow
...
>>> for x in my_accumulate(some_list):
...     print x  # or something more useful
...
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]

This works but is there an operation I could use with itertools.accumulate to facilitate this? (I'm on Python2 but the pure-python implementation/equivalent has been provided in the docs.)

Another problem I have with my_accumulate is that it doesn't work well with list(), it outputs the entire some_list for each element in the list:

>>> my_accumulate(some_list)
<generator object my_accumulate at 0x0000000002EC3A68>
>>> list(my_accumulate(some_list))
[[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]

Option 1:

I wrote my own appending accumulator function to use with itertools.accumulate but considering the LoC and final useful-ness, it seems like a waste of effort, with my_accumulate being more useful, (though may fail in case of empty iterables and consumes more memory since grow keeps growing):

>>> def app_acc(first, second):
...     if isinstance(first, list):
...        first.append(second)
...     else:
...        first = [first, second]
...     return first
...
>>> for x in accumulate(some_list, app_acc):
...     print x
...
1
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
>>> list(accumulate(some_list, app_acc))  # same problem again with list
[1, [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]

(and the first returned elem is not a list, just a single item)


Option 2: Figured it would be easier to just do incremental slicing but using the ugly iterate over list length method:

>>> for i in xrange(len(some_list)):   # the ugly iterate over list length method
...   print some_list[:i+1]
...
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
like image 484
aneroid Avatar asked Jan 05 '23 11:01

aneroid


1 Answers

The easiest way to use accumulate is to make each item in the iterable a list with a single item and then the default function works as expected:

from itertools import accumulate
acc = accumulate([el] for el in range(1, 5))
res = list(acc)
# [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
like image 91
Jon Clements Avatar answered Jan 13 '23 08:01

Jon Clements