Python convert different depth list of tuples to flatten list of tuples

Question:

I have a tuple of characters like such:

p= [((4.0, 4.0), '->', ((4, 2), (4, 8)), ((2, 2), (5, 5))), ((4.0, 7.0), '->', ((4, 2), (4, 8)), ((5, 6), (3, 8)))]`

How do I convert it to a tupple so that it is like:

p = [(4.0,4.0), (4, 2), (4, 8), (2, 2), (5, 5),(4.0, 7.0), (4, 2), (4, 8), (5, 6), (3, 8) ]

`

I was trying this way but output is coming with double bracket for some

res = []
for tup in p:
    for sub_tup in tup:
        print sub_tup, type(sub_tup)
        if type(sub_tup) == tuple:
            res.append(sub_tup)
            
print(res)

Output

  [(4.0, 4.0), ((4, 2), (4, 8)), ((2, 2), (5, 5)), (4.0, 7.0), ((4, 2), (4, 8)), ((5, 6), (3, 8))] 
Asked By: amit

||

Answers:

This solution uses an external library more_itertools.

Here’s a rundown:

  1. Collapse the p structure all the way down to non-iterable elements. The result is a 1-D array/list.
  2. Remove '->' from the list.
  3. Take every two elements from the list and put them together.
from pprint import pprint
from more_itertools import collapse, sliced

p = [((4.0, 4.0), '->', ((4, 2), (4, 8)), ((2, 2), (5, 5))), ((4.0, 7.0), '->', ((4, 2), (4, 8)), ((5, 6), (3, 8)))]

p2 = collapse(p)
p3 = filter(lambda x: isinstance(x, (int, float)), p2)
p4 = sliced(list(p3), 2)

pprint(list(p4))

Result:

[[4.0, 4.0],
 [4, 2],
 [4, 8],
 [2, 2],
 [5, 5],
 [4.0, 7.0],
 [4, 2],
 [4, 8],
 [5, 6],
 [3, 8]]
Answered By: Fractalism

Use list comprehension to flatten list and then isinstance to filter out strings.

p= [((4.0, 4.0), '->', ((4, 2), (4, 8)), ((2, 2), (5, 5))), ((4.0, 7.0), '->', ((4, 2), (4, 8)), ((5, 6), (3, 8)))]

output = [m if not isinstance(m, (int, float)) else n for o in p for n in o for m in n if not isinstance(n, str)]
output = [item for i, item in enumerate(output) if output[i] != output[i-1]]

First output almost produces the right output but with a duplicate of the item preceding the ‘->’, so we just remove the duplicates in the next line.

Answered By: Michael Cao

You can flatten the list recursively manually. This is not the most elegant way to do that, but it returns the right result:

L = []
def flatten(p):
    tupFlag = 0
    for el in p:
        if type(el) == tuple:
            tupFlag = 1
            e = flatten(el)
            if e != None:
                 L.append(flatten(e))
    if tupFlag==0:
        return p

flatten(p)
print(L)
Answered By: petruz

Here’s a recursive solution, traversing iterables until a 2-tuple of numbers is found, and ignoring anything non-iterable.

from pprint import pprint

p = [((4.0, 4.0), '->', ((4, 2), (4, 8)), ((2, 2), (5, 5))), ((4.0, 7.0), '->', ((4, 2), (4, 8)), ((5, 6), (3, 8)))]

def get_pairs(item):
    pairs = []
    if isinstance(item, (list, tuple)):
        # if item is a pair of numbers
        if (len(item) == 2 and 
            isinstance(item[0], (int, float)) and 
            isinstance(item[1], (int, float))):
            return [item]
        else:
            # item is a non-basic iterable
            for subitem in item:
                pairs.extend(get_pairs(subitem))
    else:
        # item is not list or tuple, ignore it
        pass
    return pairs

x = get_pairs(p)

pprint(x)

Result:

[(4.0, 4.0),
 (4, 2),
 (4, 8),
 (2, 2),
 (5, 5),
 (4.0, 7.0),
 (4, 2),
 (4, 8),
 (5, 6),
 (3, 8)]
Answered By: Fractalism

You can write a recursive solution like the below:

p = [((4.0, 4.0), '->', ((4, 2), (4, 8)), ((2, 2), (5, 5))), ((4.0, 7.0), '->', ((4, 2), (4, 8)), ((5, 6), (3, 8)))]

def rec_flat(tpl, result):
    for t in tpl:
        if type(t[0]) not in [str, tuple]:
            result.append(t)
        elif isinstance(t, tuple):
            rec_flat(t, result)



result = []
rec_flat(p, result)
print(result)

Output:

[(4.0, 4.0), (4, 2), (4, 8), (2, 2), (5, 5), (4.0, 7.0), (4, 2), (4, 8), (5, 6), (3, 8)]
Answered By: I'mahdi
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.