Перелічити розуміння у вкладеному списку?


219

У мене цей вкладений список:

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]

Але тоді результат - це купа 100 з сумою 2400.

будь-яке рішення, пояснення були б дуже вдячні. Дякую!


15
Ви також хочете вирівняти свій список?
— Грег Хьюгілл

@GregHewgill: ОП не відповів, але, виходячи з прийнятої відповіді, схоже, вони хотіли зберегти вкладення як є.
— smci

Відповіді:


318

Ось як це можна зробити з розумінням вкладеного списку:

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

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


191

Ось як перетворити вкладені для циклу в розуміння вкладеного списку:

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

Ось як працює розуміння вкладеного списку:

            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

Це, мабуть, одне пояснення, яке насправді б’є зі мною додому, дякую!
— Дуглас Пламлі

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

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

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

Принцип полягає в тому: використовуйте той самий порядок, який ви використовували при написанні його, як вкладений для циклів.


це має бути відповіддю, оскільки кілька разів ми не хочемо закреслювати дужку iteratool
— цинкуючи

1
це може бути не правильною відповіддю, оскільки він видає не вкладений список, але саме це я шукав, особливо принцип . Дякую!
— Родріго Е. Принсіпі

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щоб повернути генераторів поза розуміннями.
— javadba

3

У мене була подібна проблема для вирішення, тому я натрапив на це питання. Я зробив порівняння виступу Ендрю Кларка та відповіді Нараяна, яким я хотів би поділитися.

Основна різниця між двома відповідями полягає в тому, як вони перебираються над внутрішніми списками. Один з них використовує вбудовану карту , а інший використовує розуміння списку. Функція карти має незначну перевагу у порівнянні з аналогічним списком, якщо вона не вимагає використання лямбда . Отже в контексті цього питання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. Це стандарт фактичного в пітоні. Зазвичай люди більш досвідчені та зручні (особливо для початківців) у використанні розуміння списку, ніж map.



2

Цю проблему можна вирішити, не використовуючи для циклу. Єдиного коду рядка буде достатньо для цього. Використання вкладеної карти з функцією лямбда також працюватиме тут.

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
Чи є у лямбдасів якісь переваги від продуктивності порівняно з рішеннями @Andrew Clark або Гаррі Бінсвангера (більше розуміння списку ванілі)? Як лямбди здається важче читати.
— 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
Гаразд, так мабуть, це спроба відповісти на питання. Однак, мабуть, йдеться про зовсім інший сценарій, ніж в ОП, ви навіть не вживаєте вкладені списки як вхідні дані, і навіть якщо ви зміните, що ваша пропозиція є значною мірою з того, що ОП вже намагалася. Крім того, я не бачу, як приклад про карти допомагає, коли питання про перетворення рядків у плаваючі.
— Baum mit Augen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.