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


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.