Понимание списка во вложенном списке?


220

У меня есть этот вложенный список:

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']]

Теперь я хочу преобразовать каждый элемент списка в плавающее. Мое решение таково:

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

Но можно ли это сделать, используя понимание вложенного списка, верно?

что я сделал, это:

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

Но тогда получается куча сотен с суммой 2400.

Любое решение, объяснение будет высоко ценится. Спасибо!


15
Вы также хотите сгладить свой список?
— Грег Хьюгилл

@GregHewgill: OP не ответил, но, основываясь на принятом ими ответе, кажется, что они хотели сохранить вложение как есть.
— августа

Ответы:


319

Вот как вы могли бы сделать это с пониманием вложенного списка:

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

Это даст вам список списков, похожий на тот, с которого вы начали, за исключением случаев с плавающими вместо строк. Если вы хотите один плоский список, то вы бы использовали [float(y) for x in l for y in x].


192

Вот как конвертировать вложенный цикл для понимания вложенного списка:

введите описание изображения здесь

Вот как работает понимание вложенного списка:

            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]

Для вашего случая это будет примерно так.

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

21
Супер полезно! Проясняет, что петли (сверху вниз) расположены в генераторе слева направо. Это не очевидно, так как (f(x) for x in l)местами вторая строка цикла for эквивалентна слева.
— user48956

Похоже, это единственное объяснение, которое на самом деле поражает меня, спасибо!
— Дуглас Пламли

49
>>> 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

Не уверен, каков ваш желаемый результат, но если вы используете понимание списка, порядок следует за порядком вложенных циклов, который у вас есть в обратном порядке. Итак, я получил то, что я думаю, вы хотите с:

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

Принцип таков: используйте тот же порядок, который вы использовали бы при записи, как вложенные для циклов.


это должен быть ответ, так как иногда мы не хотим заключать квадратный скобок итератора
— zinking

1
это может быть неправильный ответ, так как выводит не вложенный список, но это то, что я искал, особенно принцип . Спасибо!
— Родриго Э. Принсипи

4

У меня была похожая проблема, чтобы решить, поэтому я столкнулся с этим вопросом. Я сделал сравнение производительности ответа Эндрю Кларка и Нарайана, которым я хотел бы поделиться.

Основное различие между двумя ответами состоит в том, как они перебирают внутренние списки. Один из них использует встроенную карту , в то время как другой использует понимание списка. Функция карты имеет небольшое преимущество в производительности по сравнению с ее эквивалентным пониманием списка, если она не требует использования лямбда-выражений . Так что в контексте этого вопросаmap должно работать немного лучше, чем понимание списка.

Давайте сделаем тест производительности, чтобы увидеть, если это действительно так. Я использовал Python версии 3.5.0 для выполнения всех этих тестов. В первом наборе тестов я бы хотел, чтобы количество элементов в списке составляло 10, а количество списков варьировалось от 10 до 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

введите описание изображения здесь

В следующем наборе тестов я хотел бы поднять количество элементов в списках до 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

введите описание изображения здесь

Давайте сделаем смелый шаг и изменим количество элементов в списках на 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

введите описание изображения здесь

Из этих тестов мы можем сделать вывод, что mapв этом случае выигрыш в производительности превосходит понимание списка. Это также применимо, если вы пытаетесь привести к intили str. Для небольшого количества списков с меньшим количеством элементов в списке, разница незначительна. Для больших списков с большим количеством элементов в списке можно использовать mapвместо понимания списка, но это полностью зависит от потребностей приложения.

Однако я лично считаю, что понимание списка более читабельно и идиоматично, чем map. Это де-факто стандарт в Python. Обычно люди более опытны и удобны (особенно новички) в использовании понимания списка, чем map.


4

Так как я немного опоздал, но я хотел бы поделиться тем, как на самом деле работает понимание списка, особенно вложенное понимание списка:

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

на самом деле так же, как:

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

А теперь вложенный список понимания:

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

такой же как;

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)

вывод:

[[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

Если вам не нравятся вложенные списки, вы можете также использовать функцию карты ,

>>> 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]]

Ваш код генерирует объекты карты вместо списков: >>> 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>]] но добавляя дополнительный вызов в список, он работает как положено: >>> float_l = [list(map(float, nested_list)) for nested_list in l]
— pixelperfect

@pixelperfect из-за ( дезинформированного ) изменения, python3чтобы вернуть генераторы из понимания.
— Джавадба

2

Да, вы можете сделать это с помощью такого кода:

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

[float(y) for y in x for x in l]это привело бы к сотне сотен с суммой 2400.
— Мальчик Пасмо

2

Эта проблема может быть решена без использования цикла for. Для этого будет достаточно однострочного кода. Использование Nested Map с лямбда-функцией здесь также работает.

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)

И список вывода будет выглядеть следующим образом:

[[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
Есть ли у лямбда какие-либо преимущества в производительности по сравнению, скажем, с решениями Эндрю Кларка или Гарри Бинсвангера? Как лямбды кажутся труднее читать.
— StefanJCollier

0

На мой взгляд, лучший способ сделать это - использовать itertoolsпакет 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]


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

Это может быть достигнуто с помощью понимания списка:

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

1
Это не похоже на решение вопроса на вершине вообще. Обратите внимание, что все, что публикуется как ответ, должно быть попыткой ответить на вопрос, на который оно было отправлено.
— Baum mit Augen

Хотя этот фрагмент кода может решить вопрос, в том числе объяснение действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код. Также постарайтесь не переполнять ваш код пояснительными комментариями, это снижает удобочитаемость кода и пояснений!
— Филнор,

Вложено для цикла с использованием списка понимания,
— ADITYA KUMAR

1
Итак, по-видимому, это попытка ответить на вопрос. Однако, похоже, что это совсем другой сценарий, чем в OP, вы даже не имеете дело с вложенными списками в качестве входных данных, и даже если вы измените, что ваше предложение в значительной степени то, что OP уже пробовал. Кроме того, я не вижу, как помогает пример с карточками, когда речь идет о преобразовании строк в плавающее.
— Baum mit Augen
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.