tags:

views:

96

answers:

3

I know this is very similar to a few other questions, but I can't quite get this function to work correctly.

def flatten(*args):
    return list(item for iterable in args for item in iterable)

The output I'm looking for is:

flatten(1) -> [1]
flatten(1,[2]) -> [1, 2]
flatten([1,[2]]) -> [1, 2]

The current function, which I took from another SO answer, doesn't seem to produce correct results at all:

>>> flatten([1,[2]])
[1, [2]]
+5  A: 

For a quick solution, just take your second function and make it recursive.

def flatten(*args):
    output = []
    for arg in args:
        if hasattr(arg, '__iter__'):
            output.extend(flatten(*arg))
        else:
            output.append(arg)
    return output
Pieter Witvoet
+4  A: 

If you want to flatten arbitrarily nested lists you need a recursive function:

def flatten(ls):
  if isinstance(ls, list):
     return [fa for a in ls for fa in flatten(a)]
  else:
     return [ls]

(If you expect to flatten big structures this could be made more efficient by using generators instead of returning lists.)

This function can also be reused to create a function that takes multiple parameters:

def pflatten(*ls):
   return flatten(list(ls))
sth
The input argument should be `*ls`. That does make a difference, doesn't it? And `hasattr(a, '__iter__')` is slightly more versatile than `isinstance` isn't it?
Mark
@Mark: Currently the function takes one argument, and if it's a list, it flattens it. It could also be done with `*ls`, so that the function takes several parameters and creates a flat list of their concatenations. What interface you prefer is just a matter of taste, I'd say. Similar for `isinstance(a, list)` vs. `hasattr(a, '__iter__')`: It just depends what kind of result you want when you give it a list of lists of sets. A list of sets or a list of all the elements in all the sets? Depending on your requirements one or the other would be preferable.
sth
Well yes, but this question was specifically about the latter (`*ls`). I see your point about sets though... not planning on using those, but tuples should definitely be converted to a flat list.
Mark
@Mark: Oops, you are of course right, the question is about `*ls`... I edited a little additional function into my answer to cover that case :). To also cover tuples, probably the easiest way would be to add `or isinstance(ls, tuple)` to the check in `flatten()`.
sth
Your `pflatten` doesn't work. Did you try it? I get `pflatten(1,[2]) -> [(1, [2])]` which is the sort of problem I was having when I posted this Q. Don't worry about it tho..... *my* solution does seem to work ;)
Mark
A: 

Solved it...

def flatlist(*args):
    lst = []
    for a in args:
        if hasattr(a, '__iter__'): lst.extend(flatlist(*a))
        else: lst.append(a)
    return lst
Mark