Será que existe um atalho para fazer uma simples lista fora da lista em Python?
Eu posso fazer isso em um "para" loop, mas talvez haja algum cool "one-liner"? Eu tentei com reduce()
, mas eu recebo um erro.
**Código***
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)
**Mensagem de erro***
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
Dada uma lista de listas `l',
flat_list = [item para sub-lista em l para item em sub-lista]
o que significa:
flat_list = []
for sublist in l:
for item in sublist:
flat_list.append(item)
é mais rápido do que os atalhos postados até agora. (l
é a lista para aplanar).
Aqui está a função correspondente:
flatten = lambda l: [item for sublist in l for item in sublist]
Como prova, você pode utilizar o módulo timeit
na biblioteca padrão:
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop
Explicação: os atalhos baseados em +
(incluindo a utilização implícita em sum
) são, necessariamente, O(L**2)
quando existem sub-listas L -- como a lista de resultados intermediários continua a ficar mais longa, a cada passo um novo objeto da lista de resultados intermediários é alocado, e todos os itens no resultado intermediário anterior devem ser copiados (assim como alguns novos itens adicionados no final). Então, para simplificar e sem perda real de generalidade, digamos que você tenha L sublistas de I itens cada uma: o primeiro I itens são copiados L-1 vezes, o segundo I itens L-2 vezes, e assim por diante; o número total de cópias é I vezes a soma de x para x de 1 a L excluída, ou seja, I * (L**2)/2
.
A compreensão da lista gera apenas uma lista, uma vez, e copia cada item (do seu local de residência original para a lista de resultados) também exatamente uma vez.
Nota do autor: Isto é ineficiente. Mas divertido, porque monoides são incríveis. It's não é apropriado para a produção de código Python.
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Isto apenas soma os elementos do iterável passado no primeiro argumento, tratando o segundo argumento como o valor inicial da soma (se não for dado, 0
é utilizado em seu lugar e este caso lhe dará um erro).
Como você está somando listas aninhadas, você realmente recebe [1,3]+[2,4]
como resultado de sum([[1,3],[2,4]],[])
, que é igual a [1,3,2,4]
.
Note que só funciona em listas de listas. Para listas de listas de listas, você'vai precisar de outra solução.
from functools import reduce #python 3
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(lambda x,y: x+y,l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
O método extend()
no seu exemplo modifica x
em vez de retornar um valor útil (que reduce()
espera).
Uma maneira mais rápida de fazer a versão "reduzir" seria
>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]