Home > Net >  Unwrap/Flatten unbalanced List of Lists with Strings
Unwrap/Flatten unbalanced List of Lists with Strings

Time:04-07

Given the case I have the following List:

['graph_edges', ['graph_nodes'], ['graph_nodes'], ['graph_edges2', ['graph_nodes2'], ['graph_nodes2']]]

And I wish to convert it to something like:

['graph_edges', 'graph_nodes', 'graph_nodes', 'graph_edges2', 'graph_nodes2', 'graph_nodes2'] 
# I would list(set(thislist)) afterwards

There is a ton of solutions out there already but strangely for my case I can't get anything meaningful done:

from functools import reduce
import operator
reduce(operator.concat,['graph_edges', ['graph_nodes'], ['graph_nodes'], ['graph_edges2', ['graph_nodes2'], ['graph_nodes2']]])
*** TypeError: can only concatenate str (not "list") to str

Same with sum:

sum(['graph_edges', ['graph_nodes'], ['graph_nodes'], ['graph_edges2', ['graph_nodes2'], ['graph_nodes2']]], [])

This one-liner unwraps too much:

> [item for sublist in ['graph_edges', ['graph_nodes'], ['graph_nodes'], ['graph_edges2', ['graph_nodes2'], ['graph_nodes2']]] for item in sublist]
['g', 'r', 'a', 'p', 'h', '_', 'e', 'd', 'g', 'e', 's', 'graph_nodes', 'graph_nodes', 'graph_edges2', ['graph_nodes2'], ['graph_nodes2']]

Or with itertools:

>!list(itertools.chain(*lol))
['g', 'r', 'a', 'p', 'h', '_', 'e', 'd', 'g', 'e', 's', 'graph_nodes', 'graph_nodes', 'graph_edges2', ['graph_nodes2'], ['graph_nodes2']]

Disclaimer: I tried these in ipdb, so there's always a chance of a bug

My current (not working) and very unsatisfying solution is this here:

retlist= []
dedefined=['graph_edges', ['graph_nodes'], ['graph_nodes'], ['graph_edges2', ['graph_nodes2'], ['graph_nodes2']]]

for element in dedefined:
    if isinstance(element,list):
            retlist =self.getSingleElement(element)
        else:
            retlist.append(element)
    return list(set(retlist))

@classmethod
def getSingleElement(cls,element):
    if isinstance(element,list):            
            return cls.getSingleElement(*element)
    else: return element

When element reaches ['graph_edges2', ['graph_nodes2'], ['graph_nodes2']] it's failing, but I won't be able to think of something meaningful. I could either make a generator that yields new values instead of returns or iterate through every element and make it a list which can be dissolved. But none of these ideas are convincing to me

CodePudding user response:

def flatten(array):
    flat = []
    for member in array:
        if isinstance(member, (tuple, list)):
            flat.extend(flatten(member))
        else:
            flat.append(member)
    return flat

CodePudding user response:

You need to use recursion to account for the fact that the lists can be nested arbitrarily deep:

def flatten(lst):
    result = []
    for item in lst:
        # You can use:
        # if not isinstance(item, list):
        # if you have other items besides integers in your nested list.
        if isinstance(item, str):
            result.append(item)
        else:
            result.extend(flatten(item))
    return result

This outputs:

['graph_edges', 'graph_nodes', 'graph_nodes',
 'graph_edges2', 'graph_nodes2', 'graph_nodes2']
  • Related