1

Ref: python decompose a list Flattening a shallow list in Python

While the above mentioned solutions are helpful, my problem is slightly different, and I was wondering if there is a pythonic way to solve it.

a = [['a-3','b-3'],'r',['j']]

What I would like, is a clean way of making 'a' equal the following:

a = ['a-3','b-3','r','j']

I am stuck using python 2.4 so a pythonic solution that's 2.4 compatible would be great, but I would still find 2.7+ examples interesting as well.

The main problem is that there are non-iterable elements, otherwise the sum(lst,[]) works quite well, as does the chain method for 2.7+

Community
  • 1
  • 1
pyInTheSky
  • 1,459
  • 1
  • 9
  • 24

5 Answers5

5

Pythonic solution can mean many thing. With readability counts (PEP 20) in mind, this is my contribution to the thread:

def dec(input_, output_):
    if type(input_) is list:
        for subitem in input_:
            dec(subitem, output_)
    else:
        output_.append(input_)

Example:

input_ = [['a-3','b-3', ['x','hello', ['3','b']]],'r',['j']]
output_ = ['a-3', 'b-3', 'x', 'hello', '3', 'b', 'r', 'j']
mac
  • 42,153
  • 26
  • 121
  • 131
2

How about:

itertools.chain.from_iterable(map(lambda i: i if type(i) == list else [i], a))

or, for readability:

def assure_is_list(a):
   return a if type(a) == list else [a]

itertools.chain.from_iterable(map(assure_is_list, a))
rafalotufo
  • 3,862
  • 4
  • 25
  • 28
  • agreed, that works, and this will for versions prior to itertools availablility .. sum(map(lambda i: i if type(i) == list else [i],a),[]) .. though I'm not sure sum is intended to be used as a list decomposer .. I was hoping to avoid conditionals since they make things a bit messy looking s.a. sum(map(list,a),[]) .. I'm rather surprised str() and a few others can take a param but list can't – pyInTheSky Jun 27 '11 at 20:44
  • 1
    I would argue that this demonstrates good knowledge of the language but is not a really pythonic formulation (Readability counts, see my own answer). Cheers! :) – mac Jun 27 '11 at 21:01
  • @mac: Well, preference is hard to discuss. You prefer your way, I prefer mine :) If you create a function for `lambda`, with a nice name, say `assure_is_list`, it becomes very readable. – rafalotufo Jun 27 '11 at 21:06
  • Furthermore, I'd argue that this solution is much less prone to mistakes and errors. – rafalotufo Jun 27 '11 at 21:11
  • @rafalotufo - If you give a nice name to the lambda function then your one-liner would violate PEP 8! ;) [just kidding of course... your answer is totally correct and - above all - was chosen as the preferred one by the OP. I just couldn't resist! ;) ] – mac Jun 27 '11 at 21:13
  • indeed, it also doesn't solve the problem you pose in the example, in which you nest more than one level, in which case you do need the recursion. therefore, you and inspectorG4dget get equal credit since it seems you have identical solutions though one with more recursion than the other – pyInTheSky Jun 27 '11 at 21:16
2
def flatten(L):
    if not L:
        return L
    elif isinstance(L[0], list):
        return flatten(L[0]) + flatten(L[1:])
    else:
        return [L[0]] + flatten(L[1:])

Hope this helps

mrCarnivore
  • 4,638
  • 2
  • 12
  • 29
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
0

Recursive flattening of any iterable types, except leaving strings alone (since you probably don't want to split those into characters):

def flatten(x):
  try:
    if isinstance(x, basestring): raise TypeError
    y = iter(x)
  except TypeError:
    yield x
    return
  for item in y:
    for subitem in flatten(item):
      yield subitem
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
0

Think that you can also use something like this:

data = [['a-3','b-3', ['x','hello', ['3','b']]],'r',['j']]

while not all(not isinstance(x, list) for x in data):
    for i in xrange(len(data)):
        value = data.pop(i)
        if isinstance(value, list):
            data.extend(value)    
        else:
            data.append(value)
Artsiom Rudzenka
  • 27,895
  • 4
  • 34
  • 52