3
I/P - (('1', (('2355', '5'), 'F')),
       ('1', (('2300', '4'), 'M')),
       ('1', (('2400', '5'), 'F')))
O/P - [['1','2355','5','F'],
       ['1','2300','4','M'],
       ['1','2400','5','F']]

I am able to get the first element but the other elements are still extracted as a tuple whereas I want all of them to come out as part of a list. Basically, I want every element to come out individually as part of a list.

rAmAnA
  • 1,909
  • 1
  • 11
  • 11

4 Answers4

2

in 3.3+ there is a recursive idiom that can be modified to flatten nested tuples of 'any' depth (see: system recursion limit)

def yielder(x):
    for y in x:
        if isinstance(y, tuple):
            yield from yielder(y)
        else:
            yield y

which can then be used in a list comprehension

[[*yielder(e)] for e in IP]
Out[48]: [['1', '2355', '5', 'F'], ['1', '2300', '4', 'M'], ['1', '2400', '5', 'F']]

I found the above by searching for 'python flatten', in the comments to https://jugad2.blogspot.in/2014/10/flattening-arbitrarily-nested-list-in.html

for 2/7 http://joedicastro.com/aplanar-listas-en-python.html has recipes, I modded:

def flat_slice ( lst ):
    lst = list ( lst )
    for i , _ in enumerate ( lst ):
        while ( hasattr ( lst [ i ], "__iter__" ) and not isinstance ( lst [ i ], basestring )):
             lst [ i : i + 1 ] = lst [ i ]
    return lst

(I had to change basestring to str for 3+)

and it ran with the same result

[[*flat_slice(e)] for e in IP]
Out[66]: [['1', '2355', '5', 'F'], ['1', '2300', '4', 'M'], ['1', '2400', '5', 'F']]
f5r5e5d
  • 3,656
  • 3
  • 14
  • 18
0
def flaten(t,level=0):
   l = []
   for t1 in t:
     if type(t1) is tuple:
       if level == 0:
         l.append(flaten(t1,level+1))
       else:
         l.extend(flaten(t1,level+1))
     else:
       l.append(t1)
   return l

t = (('1', (('2355', '5'), 'F')), ('1', (('2300', '4'), 'M')), ('1', (('2400', '5'), 'F')))
l = flaten(t)
print(l)
Serjik
  • 10,543
  • 8
  • 61
  • 70
0

I kept it to a simple recursive routine that can also be used in a comprehension:

def unpack(element, stack):
    if isinstance(element, basestring):
        stack.append(element)
    else:
        for i in element:
            unpack(i, stack)
    return stack

[unpack(row, []) for row in IP]

Output:

[['1', '2355', '5', 'F'], ['1', '2300', '4', 'M'], ['1', '2400', '5', 'F']]
RobertB
  • 1,879
  • 10
  • 17
  • What is basestring? – Pitto Dec 04 '19 at 20:53
  • Google is your friend: “ basestring()¶ This abstract type is the superclass for str and unicode. It cannot be called or instantiated, but it can be used to test whether an object is an instance of str or unicode. isinstance(obj, basestring) is equivalent to isinstance(obj, (str, unicode)).” – RobertB Dec 21 '19 at 18:30
0

Iterate each iterable, flatten all elements, then recast the iterable to a list. Here are two approaches:

Given

iterables = (
    ('1', (('2355', '5'), 'F')),
    ('1', (('2300', '4'), 'M')),
    ('1', (('2400', '5'), 'F'))
)

expected = [
    ['1','2355','5','F'],
    ['1','2300','4','M'],
    ['1','2400','5','F']
]

Code

A modified flatten from this post (Python 2/3 compatible):

# Approach 1
from collections import Iterable


def flatten(items):
    """Yield items from any nested iterable"""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            for i in flatten(x):
                yield i
        else:
            yield x

actual = [list(flatten(i)) for i in iterables]
assert actual == expected

For a one-liner, consider more_itertools.collapse, a tool that also flattens nested iterables:

# Approach 2
import more_itertools as mit


actual = [list(mit.collapse(i)) for i in iterables]
assert actual == expected

Note: more_itertools is a third-party library that implements several itertools recipes and useful tools. Install by pip install more_itertools.

pylang
  • 40,867
  • 14
  • 129
  • 121