What if you had a list like this: [1, -10, [1,2,[3,4]], xrange(200)], and you just wanted to go through each element in order (wanted it to return a simple list of [1,-10,1,2,3,4,1,2,3,4...199])
I've seen a couple of attempts to flatten arbitrarily deep lists. Many of them involve recursion, like this one: http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html
Recursion is generally considered non-pythonic (at least to my knowledge), so I have used one which just involves simple iterators instead. Also, recursion will fail if the list is too deep (so it wouldn't really be arbitrary, would it?).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
class iter2(object): '''Takes in an object that is iterable. Allows for the following method calls (that should be built into iterators anyway...) calls: - append - appends another iterable onto the iterator. - insert - only accepts inserting at the 0 place, inserts an iterable before other iterables. - adding. an iter2 object can be added to another object that is iterable. i.e. iter2 + iter (not iter + iter2). It's best to make all objects iter2 objects to avoid syntax errors. :D ''' def __init__(self, iterable): self._iter = iter(iterable) def append(self, iterable): self._iter = itertools.chain(self._iter, iter(iterable)) def insert(self, place, iterable): if place != 0: raise ValueError('Can only insert at index of 0') self._iter = itertools.chain(iter(iterable), self._iter) def __add__(self, iterable): return itertools.chain(self._iter, iter(iterable)) def next(self): return self._iter.next() def __iter__(self): return self def flatten(iterable): '''flatten a list of any depth''' iterable = iter2(iterable) for e in iterable: if hasattr(e, '__iter__'): iterable.insert(0, e) else: yield e
It's slow (like 10 times slower than the solutions here: http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python?answertab=active#tab-top) but unlike those it handles lists of any depth.
Note: that this will not split up non-iterables (it won't split up combinations, like strings).
Note: be careful, as this can almost be too general. Anything that has an iterator in it will be split up, so if you have dictionaries in your list their keys will be extracted (and no exception will be raised). On the other hand, it will also work if you have numpy arrays or other such iterables (such as xrange).