Flatten list of lists. Is a more concise solution possible?

5

I solved the following Python exercise:

  

Implement a function that receives a list of length lists   and return a list of one dimension.

The solution I was able to do was as follows:

#!/usr/bin/env python
#-*- coding: utf-8 -*-

def list_unifier(lista_de_listas):
    lista_unificada = []
    for i in range(0, len(lista_de_listas)):
        for j in range(0, len(lista_de_listas[i])):
            lista_unificada.append(lista_de_listas[i][j])

    return lista_unificada

print list_unifier([[1, 2], [3, 4, 5], [], [6, 7]])

Output:

[1, 2, 3, 4, 5, 6, 7]

The question is, would this be the best way to do it? I found it to be very prolix.

I was thinking of something involving for i in lista_de_listas or something.

    
asked by anonymous 10.03.2018 / 13:44

4 answers

7

An idea that shortens your code without calling additional packages is:

def list_unifier(lista_de_listas):
    lista_unificada = []
    for lista in lista_de_listas:
        for elemento in lista:
            lista_unificada.append(elemento)
    return lista_unificada

Calling the function:

print(list_unifier([[1, 2], [3, 4, 5], [], [6, 7]])) # Sintaxe válida para Python 3 ou 2 
print list_unifier([[1, 2], [3, 4, 5], [], [6, 7]]) # Sintaxe válida apenas para Python 2

Result:

[1, 2, 3, 4, 5, 6, 7]

I've renamed the iterators of every for loop to make it easier to understand. First we use for to select each list in the list of lists. Next, we use a second for to get each element in the selected list. Since we select the element and not its position, we do not have to use indexes to make append , just call lista_unificada.append(elemento) .

    
10.03.2018 / 14:27
5

In the style of antigravity and, in general, more pythonic , you can use the native module itertools to solve the problem, more specifically the chain function, which does exactly what you want (that is, the function you are asked to deploy already exists natively).

from itertools import chain

listas = [[1, 2], [3, 4, 5], [], [6, 7]]
resultado = list(chain(*listas))

print(resultado)

It will be printed [1, 2, 3, 4, 5, 6, 7] . It is important to note that this solution uses deconstruction of lists, with the * operator preceding the object and that the chain return is a generator, which can greatly optimize the solution since it would not be necessary to have a complete copy of all values in memory.

I am aware that the purpose of the exercise was precisely to define the function to apply the basic concepts, mainly repetition loops, but I believe that studying the concepts applied to the present solution are fundamental and so I decided to post the answer. / p>     

10.03.2018 / 14:59
4

reduce !

Python2:

listas = [[1, 2], [3, 4, 5], [], [6, 7]]
reduce(lambda prev, next: prev + next, listas)
[1, 2, 3, 4, 5, 6, 7]

This is for lists of lists. But for lists of list lists ... anyway, and for arbitrary depth? reduce recursive!

lista = [[10], [20, 30], [20, [40, 50, 60, [79, [40, [59, 66, 77]]]]]]
def makeItFlat(lista):
    return [lista] if not isinstance(lista, list) else reduce(lambda x, y: makeItFlat(x) + makeItFlat(y), lista, [])
res = makeItFlat(lista)
print(res)

[10, 20, 30, 20, 40, 50, 60, 79, 40, 59, 66, 77]

Note: in Python3 reduce found in functools module.

    
15.03.2018 / 18:29
3

Current responses "leave blank" lists of lists. In that case, leaving shallow is all in the same depth. Objects that were once at a depth of 2 lists are in the depth of a list only. What if it were possible to inform an arbitrary depth to "leave shallow"? For example, the deep list ...

[1, 2, [[[3, [4], 5, [6, 7, [[8, 9], 10, [11]], 12], 13], 14], 15], 16, [17, [[[18]]], 19], 20]

... would be transformed into this shallow list:

[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

The idea to solve this problem is to have a recursive function shallowfy (I believe that "scratching" does not have the same impact, so I preferred to use the English version myself) to do the service. The shallowfy entry is a list and its return is a shallow list. Its operation is as follows:

  • start with an empty list shallow
  • for each element el of the input list
    • If el is not a list, add el at the end of shallow
    • If el is a list, I get shallow_el = shallowfy(el)
    • I add all elements of shallow_el at the end of shallow
  • returns shallow
  • The function looks like this:

    def shallowfy(lista):
      shallow = []
      for el in lista:
        if (isinstance(el, list)):
          shallow_el = shallowfy(el)
          for subel in shallow_el:
            shallow.append(subel)
        else:
          shallow.append(el)
      return shallow
    

    See working at ideone .

    References:

    15.03.2018 / 17:24