Python Forum

Full Version: flattening a list with some elements being lists
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
a list might be like [[1,2,3],4,[5,6,7,8],[9]] and i want to flatten it to [1,2,3,4,5,6,7,8,9]. how easy is this to do if it is only 2 levels like that? what if it goes even deeper like [[1,2,3],4,[5,[[6,7],8]],[9]]. is it any easier as a list than any type of iterator? would this be any easier if the iterators were ranges?
There is a generator function here. Look at it.
looking for something simpler. i think i am getting close.
This could be simpler and should work:

>>> m = [[1,2,3],4,[5,[[6,7],8]],[9]]
>>> def flatten(lst):
...     for item in lst:
...         try:
...             yield from flatten(item)
...         except TypeError:
...             yield item
...
>>> list(flatten(m))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
I should mention that if list contains string(s) function fails miserably (maximum recursion depth exceeded)
you could test for list type somewhere to avoid trying to iterate a string.

* Skaperen thinks that code would be a great example for the language reference

that code gave me hints, but i wanted something that would also work in Python2, so no yield from. i came up with this code, which works without being a generator at all. i created it as a code file with test code, instead of an interactive session, since i wanted to keep it.

flatten.py:
def flatten(*a):
    if len(a)==1:
        l=[]
        flatten(a[0],l)
        return l
    if isinstance(a[0],list):
        for e in a[0]:
            flatten(e,a[1])
        return
    a[1].append(a[0])
    return

x=[[1,2,3],4,[5,[[6,7],8]],[9]]
print(repr(x))
y=flatten(x)
print(repr(y))
(Aug-06-2018, 06:03 AM)perfringo Wrote: [ -> ]I should mention that if list contains string(s) function fails miserably (maximum recursion depth exceeded)
I had this issue with strings. You can see the link in my prev. post.
I like the way you use try/except. I didn't even think to catch an exception.
Let's bend our minds little further Smile

This should be compatible with Python 2 and handle strings as well:

def flatten(lst):
    def _flatten(lst, result):    
        if type(lst) is not list:
            result.append(lst)
        else:
            for item in lst:
                result = result + flatten(item)
        return result
    return _flatten(lst, [])
This will produce:
>>> n = [[1, 2, 3], [[4]], [5], [['spam','ham','bacon'] , [['foo','bar','baz']], ['x','y','z']], 6]
>>> flatten(n)
[1, 2, 3, 4, 5, 'spam', 'ham', 'bacon', 'foo', 'bar', 'baz', 'x', 'y', 'z', 6]
def flatten(lst):
    result = []
    for item in lst:
        if isinstance(item, (list, tuple)): # You may add more container types if needed
            result.extend(flatten(item))
        else:
            result.append(item)
    return result
    
n = [[1, 2, 3], [[4]], [5], [['spam','ham','bacon'] , [['foo','bar','baz']], ('x','y','z')], 6]
print flatten(n)
Output:
[1, 2, 3, 4, 5, 'spam', 'ham', 'bacon', 'foo', 'bar', 'baz', 'x', 'y', 'z', 6]
(Aug-06-2018, 10:18 AM)buran Wrote: [ -> ]
def flatten(lst):
    result = []
    for item in lst:
        if isinstance(item, (list, tuple)): # You may add more container types if needed
            result.extend(flatten(item))
        else:
            result.append(item)
    return result
    

This is the reason I like Python - smart people (like buran) can achieve desired results with minimal and very readable piece of code. I have lot of work to do in smart part Smile
Using a generic function to dispatch according to the argument's type
>>> import functools
>>> @functools.singledispatch
... def flatten(x):
...     return [x]
... 
>>> @flatten.register(list)
... @flatten.register(tuple)
... def _(x):
...     return [z for y in x for z in flatten(y)]
... 
>>> a = [[1, 2, 3], [[4]], [5], [['spam','ham','bacon'] , [['foo','bar','baz']], ('x','y','z')], 6]
>>> flatten(a)
[1, 2, 3, 4, 5, 'spam', 'ham', 'bacon', 'foo', 'bar', 'baz', 'x', 'y', 'z', 6]
Pages: 1 2