Compreensão de lista em uma lista aninhada?


219

Eu tenho esta lista aninhada:

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

Agora, o que eu quero fazer é converter cada elemento em uma lista para flutuar. Minha solução é esta:

newList = []
for x in l:
  for y in x:
    newList.append(float(y))

Mas isso pode ser feito usando compreensão de lista aninhada, certo?

o que eu fiz é:

[float(y) for y in x for x in l]

Mas o resultado é um monte de 100 com a soma de 2400.

qualquer solução, uma explicação seria muito apreciada. Obrigado!


15
Deseja também achatar sua lista?
Greg Hewgill

@ GregHewgill: O OP não respondeu, mas com base na resposta que eles aceitaram, parece que eles queriam manter o aninhamento como está.
smci 02/02

Respostas:


317

Aqui está como você faria isso com uma compreensão de lista aninhada:

[[float(y) for y in x] for x in l]

Isso forneceria uma lista de listas, semelhante à que você começou, exceto com flutuadores em vez de cadeias. Se você quiser uma lista simples, então usaria [float(y) for x in l for y in x].


190

Aqui está como converter o nested for loop em compreensão de lista aninhada:

insira a descrição da imagem aqui

Aqui está como a compreensão da lista aninhada funciona:

            l a b c d e f
                  
In [1]: l = [ [ [ [ [ [ 1 ] ] ] ] ] ]
In [2]: for a in l:
   ...:     for b in a:
   ...:         for c in b:
   ...:             for d in c:
   ...:                 for e in d:
   ...:                     for f in e:
   ...:                         print(float(f))
   ...:                         
1.0

In [3]: [float(f)
         for a in l
   ...:     for b in a
   ...:         for c in b
   ...:             for d in c
   ...:                 for e in d
   ...:                     for f in e]
Out[3]: [1.0]

Para o seu caso, será algo parecido com isto.

In [4]: new_list = [float(y) for x in l for y in x]

21
Super útil! Torna claro que os loops (de cima para baixo) são ordenados da esquerda para a direita no gerador. Isso não é óbvio, pois (f(x) for x in l)coloca a segunda linha do equivalente for-loop à esquerda.
precisa saber é o seguinte

Esta parece ser a única explicação que está realmente chegando em casa comigo, obrigado!
Douglas Plumley 20/03

48
>>> l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]
>>> new_list = [float(x) for xs in l for x in xs]
>>> new_list
[40.0, 20.0, 10.0, 30.0, 20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0, 30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]

42

Não tenho certeza qual é a saída desejada, mas se você estiver usando a compreensão da lista, a ordem seguirá a ordem dos loops aninhados, que você tem para trás. Então, eu tenho o que eu acho que você quer com:

[float(y) for x in l for y in x]

O princípio é: use a mesma ordem que você usaria para escrevê-lo como aninhado para loops.


esta deve ser a resposta, como algumas vezes nós não queremos colchete o iteratool
zinking

1
essa pode não ser a resposta correta, pois gera uma lista não aninhada, mas é o que eu estava procurando, especialmente o princípio . Obrigado!
Rodrigo E. Principe

4

Como estou um pouco atrasado aqui, mas queria compartilhar como realmente funciona a compreensão da lista, especialmente a compreensão da lista aninhada:

New_list= [[float(y) for x in l]

é realmente o mesmo que:

New_list=[]
for x in l:
    New_list.append(x)

E agora compreensão de lista aninhada:

[[float(y) for y in x] for x in l]

é o mesmo que;

new_list=[]
for x in l:
    sub_list=[]
    for y in x:
        sub_list.append(float(y))

    new_list.append(sub_list)

print(new_list)

resultado:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

3

Se você não gosta da compreensão de listas aninhadas, também pode usar a função de mapa ,

>>> from pprint import pprint

>>> l = l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']] 

>>> pprint(l)
[['40', '20', '10', '30'],
['20', '20', '20', '20', '20', '30', '20'],
['30', '20', '30', '50', '10', '30', '20', '20', '20'],
['100', '100'],
['100', '100', '100', '100', '100'],
['100', '100', '100', '100']]

>>> float_l = [map(float, nested_list) for nested_list in l]

>>> pprint(float_l)
[[40.0, 20.0, 10.0, 30.0],
[20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0],
[30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0],
[100.0, 100.0],
[100.0, 100.0, 100.0, 100.0, 100.0],
[100.0, 100.0, 100.0, 100.0]]

Seu código gera objetos de mapa em vez de listas: >>> float_l = [map(float, nested_list) for nested_list in l] [[<map at 0x47be9b0>], [<map at 0x47be2e8>], [<map at 0x47be4a8>], [<map at 0x47beeb8>], [<map at 0x484b048>], [<map at 0x484b0b8>]] mas acrescentando uma chamada adicional à lista funciona como esperado: >>> float_l = [list(map(float, nested_list)) for nested_list in l]
PixelPerfect

@pixelperfect devido à alteração ( desinformada ..) python3para devolver geradores fora de compreensão.
Javadba 4/03

3

Eu tinha um problema semelhante para resolver, então me deparei com essa pergunta. Fiz uma comparação de desempenho das respostas de Andrew Clark e Narayan que gostaria de compartilhar.

A principal diferença entre duas respostas é como elas iteram nas listas internas. Um deles usa o mapa interno , enquanto outro está usando a compreensão da lista. A função de mapa tem uma pequena vantagem de desempenho para sua compreensão equivalente da lista, se não exigir o uso de lambdas . Portanto, no contexto desta questão map, o desempenho deve ser um pouco melhor que a compreensão da lista.

Vamos fazer um benchmark de desempenho para ver se é realmente verdade. Eu usei o python versão 3.5.0 para realizar todos esses testes. No primeiro conjunto de testes, eu gostaria de manter os elementos por lista em 10 e variar o número de listas de 10 a 100.000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10]"
>>> 100000 loops, best of 3: 15.2 usec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100]"
>>> 100000 loops, best of 3: 15.2 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*1000]"
>>> 1000 loops, best of 3: 1.43 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*1000]"
>>> 100 loops, best of 3: 1.91 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10000]"
>>> 100 loops, best of 3: 13.6 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10000]"
>>> 10 loops, best of 3: 19.1 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 164 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 216 msec per loop

insira a descrição da imagem aqui

No próximo conjunto de testes, gostaria de aumentar o número de elementos por lista para 100 .

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 110 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 151 usec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.11 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.5 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 11.2 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 16.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 134 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 171 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.32 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.7 sec per loop

insira a descrição da imagem aqui

Vamos dar um passo corajoso e modificar o número de elementos nas listas para 1000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 800 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 1.16 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 8.26 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 11.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 83.8 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 118 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 868 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 1.23 sec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 9.2 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 12.7 sec per loop

insira a descrição da imagem aqui

A partir desses testes, podemos concluir que maphá um benefício de desempenho sobre a compreensão da lista nesse caso. Isso também é aplicável se você estiver tentando transmitir para um intou outro str. Para um pequeno número de listas com menos elementos por lista, a diferença é insignificante. Para listas maiores com mais elementos por lista, pode-se usar em mapvez da compreensão da lista, mas isso depende totalmente das necessidades do aplicativo.

No entanto, eu pessoalmente acho a compreensão da lista mais legível e idiomática do que map. É um padrão de fato em python. Geralmente, as pessoas são mais eficientes e confortáveis ​​(especialmente iniciantes) no uso da compreensão de listas do que map.


2

Sim, você pode fazer isso com esse código:

l = [[float(y) for y in x] for x in l]

[float(y) for y in x for x in l]isso resultaria para um bando de 100 Com uma soma de 2400.
Boy Pasmo

2

Este problema pode ser resolvido sem o uso do loop for. O código de linha única será suficiente para isso. O uso do Mapa Aninhado com a função lambda também funciona aqui.

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

map(lambda x:map(lambda y:float(y),x),l)

E a lista de saída seria a seguinte:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

1
As lambdas têm algum benefício de desempenho em relação às soluções de @Andrew Clark ou Harry Binswanger (mais compreensão da lista de baunilha)? Como lambdas parecem mais difíceis de ler.
precisa saber é o seguinte

0

A melhor maneira de fazer isso na minha opinião é usar o itertoolspacote do python .

>>>import itertools
>>>l1 = [1,2,3]
>>>l2 = [10,20,30]
>>>[l*2 for l in itertools.chain(*[l1,l2])]
[2, 4, 6, 20, 40, 60]

0

Sim, você pode fazer o seguinte.

[[float(y) for y in x] for x in l]

-2
    deck = [] 
    for rank in ranks:
        for suit in suits:
            deck.append(('%s%s')%(rank, suit))

Isso pode ser alcançado usando a compreensão da lista:

[deck.append((rank,suit)) for suit in suits for rank in ranks ]

1
Isso não parece abordar a questão no topo. Observe que tudo postado como resposta deve ser uma tentativa de responder à pergunta para a qual ele foi postado.
Baum mit Augen

Embora esse trecho de código possa resolver a questão, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código. Por favor, tente também não sobrecarregar seu código com comentários explicativos, isso reduz a legibilidade do código e das explicações!
Filnor 22/03/19

Aninhado para loop usando compreensão de lista,
ADITYA KUMAR

1
Ok, aparentemente, essa é uma tentativa de responder à pergunta. No entanto, esse parece ser um cenário totalmente diferente do OP, você nem lida com listas aninhadas como entrada e, mesmo que mude, sua sugestão é basicamente o que o OP já tentou. Além disso, não vejo como um exemplo sobre cartões ajuda quando a pergunta é sobre a conversão de cadeias para flutuar.
Baum mit Augen
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.