Welcome, guest | Sign In | My Account | Store | Cart

I created this function sometime ago for my own purposes. It simply flattens a list.

Check out the first comment for another version of someone else's design.

Python, 8 lines
1
2
3
4
5
6
7
8
# flattens a list eg. flatten(1, 2, ['b','a','c']) = [1, 2, 'a', 'b', 'c']
def flatten(*args):
    for x in args:
        if hasattr(x, '__iter__'):
            for y in flatten(*x):
                yield y
        else:
            yield x

7 comments

Sherry Xue 13 years, 10 months ago  # | flag

How about this?

def flatten(*args):
    for x in args:
        if hasattr(x, '__iter__'):
            for y in flatten(*x):
                yield y
        else:
            yield x

>>> list(flatten(1, 2, ['b', 'a', 'c']))
[1, 2, 'b', 'a', 'c']
Sunjay Varma (author) 13 years, 9 months ago  # | flag

I am not that familiar with the yield statement. Could you please explain further?

Giannis Fysakis 13 years, 9 months ago  # | flag

Sherry that's brilliant with way less code and all the goodies from generators ;) way better than other's version ...

Sunjay Varma as you can see there are always more efficient ways to code things , especially in interpreted languages , so it is not polite to criticize other people codes in that manner ... in my opinion this site supposed to be about learning and sharing not judging ...

Sunjay Varma (author) 13 years, 9 months ago  # | flag

Sorry about that. I didn't mean to seem rude. I only posted because I thought that the community would benefit from different versions of functions.

Thanks to this recipe, we now have a great generator version as well.

-Sunjay03

Sunjay Varma (author) 13 years, 9 months ago  # | flag

Just something to add, Sherry's recipe above is very good for iteration, but for list stuff, you would have to add the extra statement

list(flatten([1],23,[21],[213,1]))

Which might be inconvenient for some people.

-Sunjay03

Sherry Xue 13 years, 9 months ago  # | flag

Sorry back so late, I do not always online.

Sunjay Varma, as you see, generator is a simpler, faster and more memory efficient way(I like it ^ ^). For more information, you can read the python official documentation: http://docs.python.org/reference/simple_stmts.html#the-yield-statement.

Except generators, I used "hasattr(x, '__iter__')" instead of "isinstance(x, (list, tuple))" to check the argument can be iterative. Not only list and tuple, I hoped it also work for set, xrange(python 2.x), generator and iterator types. For example:

>>> a = 1  # int
>>> b = 'abc'  # str
>>> c = (2, 3, 4)  # tuple
>>> d = ['d', 'e', 'f']  # list
>>> e = set((5, 6))  # set
>>> f = xrange(2)  # xrange
>>> g = (i*2 for i in f)  # generator
>>> list(flatten(a, b, c, d, e, f, g))
[1, 'abc', 2, 3, 4, 'd', 'e', 'f', 5, 6, 0, 1, 0, 2]

More information: http://docs.python.org/library/stdtypes.html#built-in-types.

Lastly, I prefer to use generators if there is not necessary to get all elements and creat a list to memorize them. Maybe using a for loop is better?

>>> for i in flatten(a, b, c, d, e, f, g):
        print i,    
1 abc 2 3 4 d e f 5 6 0 1

Sorry for my poor English. Enjoy.

Sunjay Varma (author) 13 years, 1 month ago  # | flag

Thanks I agree completely. :)

Created by Sunjay Varma on Sat, 5 Jun 2010 (MIT)
Python recipes (4591)
Sunjay Varma's recipes (12)

Required Modules

  • (none specified)

Other Information and Tasks