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

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]
falsetru
источник
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]
Thomasillo
источник
0

Да, вы можете сделать следующее.

[[float(y) for y in x] for x in l]
user1142317
источник
-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