Home > OS >  plain list from list of lists of lists
plain list from list of lists of lists

Time:12-09

i have a list like this:

list1=[['milk', 'bread', 'eggs'], ['eggs', ['milk'], 'bread']]

I want to flatten (expected outcome):

list1=[['milk', 'bread', 'eggs'], ['eggs', 'milk', 'bread']]

I am using this code:

flat_list = []
for sublist in list1:
    for item in sublist:
        flat_list.append(item)

But i get back:

list1=['milk', 'bread', 'eggs', 'eggs', ['milk'], 'bread']

Any ideas?

CodePudding user response:

You can check if you're hitting a list or not and if it's a list, extend it, if not append it.

flat_list = []
for sublist in list1:
    flat_list.append([])
    for x in sublist:
        if isinstance(x, list):
            flat_list[-1].extend(x)
        else:
            flat_list[-1].append(x)

Output:

[['milk', 'bread', 'eggs'], ['eggs', 'milk', 'bread']]

But this wouldn't work if you have something like:

[['milk', ['bread', ['eggs']]]]

Or you can use the following function (that does not use recursion, so it will be faster):

def flatten_list(list1):
    out = []
    inside = list1
    while inside:
        x = inside.pop(0)
        if isinstance(x, list):
            inside = x   inside
        else:
            out.append(x)
    return out

out = [flatten_list(sublist) for sublist in list1]

flatten_list([['milk', ['bread', ['eggs']]]]) #['milk', 'bread', 'eggs']

CodePudding user response:

Here is the code that can solve your problem

list1 = [['milk', 'bread', 'eggs'], ['eggs', ['milk'], 'bread']]

flat_list = []
for i in list1:
    temp_list =[]
    for j in i:
        if type(j) is list:
            temp_list.append(j[0])
        else:
            temp_list.append(j)
    flat_list.append(temp_list)

Now the flat_list output is

[['milk', 'bread', 'eggs'], ['eggs', 'milk', 'bread']]

CodePudding user response:

You can use a recursive generator to flatten the list with an arbitrary nesting level (only limited by recursion depth):

list1=[['milk', 'bread', 'eggs'], ['eggs', ['milk'], 'bread']]

def flatten(iterable):
    from collections.abc import Iterable
    for item in iterable:
        if isinstance(item, Iterable) and not isinstance(item, str):
            yield from flatten(item)
        else:
            yield item
            
list(flatten(list1))

output: ['milk', 'bread', 'eggs', 'eggs', 'milk', 'bread']

To only flatten after the first level:

out = [list(flatten(l)) for l in list1]

output: [['milk', 'bread', 'eggs'], ['eggs', 'milk', 'bread']]

CodePudding user response:

Yet another one (this time using a recursive generator function):

list1 = [
    ['milk', 'bread', 'eggs'], 
    ['eggs', ['milk'], 'bread'], 
    [[['eggs']], 'milk', [['bread']]]
]

def flatten(lst):
    for item in lst:
        if isinstance(item, list):
            yield from flatten(item)
        else:
            yield item

list2 = [list(flatten(sublist)) for sublist in list1]
print(list2)

This will yield

[['milk', 'bread', 'eggs'], ['eggs', 'milk', 'bread'], ['eggs', 'milk', 'bread']]

CodePudding user response:

A recursive function is probably the easiest way to handle this:

def flatten(L):
    return [f for v in L for f in flatten(v)] if isinstance(L,list) else [L]


list1=[['milk', 'bread', 'eggs'], ['eggs', ['milk'], 'bread']]
print(flatten(list1))
['milk', 'bread', 'eggs', 'eggs', 'milk', 'bread']

You could also use an iterative approach (doing it in-place for this example):

def flatten(L):
    for i,_ in enumerate(L):
        while isinstance(L[i],list):
            L[i:i 1] = L[i]

list1=[['milk', 'bread', 'eggs'], ['eggs', ['milk'], 'bread']]
flatten(list1)
print(list1)
['milk', 'bread', 'eggs', 'eggs', 'milk', 'bread']

The use of enumerate() in the for loop is to continually get additional indexes as the list grows

  • Related