Розуміння розуміння вкладеного списку


74

Я хочу зрозуміти розуміння вкладеного списку. Нижче я перерахував вираз для розуміння списку та їх еквівалент циклу for.
Цікаво, чи правильно я розумію це?

Наприклад,

[(min([row[i] for row in rows]),max([row[i] for row in rows])) 
for i in range(len(rows[0]))]

еквівалентно

result=[]
for i in range(len(rows[0])):
  innerResult=[]
  for row in rows:
    innerResult.append(row[i])
  innerResult2=[]
  for row in rows:
    innerResult2.append(row[i])
  tuple=(min(innerResult), max(innerResult2))
  result.append(tuple)

Якщо я можу узагальнити, я здогадуюсь

[exp2([exp1 for x in xSet]) for y in ySet]

форму можна перекласти на наступний. (Сподіваюся, я правильно в цьому)

result=[]
for y in ySet:
  innerResult =[]
  for x in xSet:
    innerResult.append(exp1)
  exp2Result = exp2(innerResult)
  result.append(exp2Result)

Для більш простого випадку

[exp1 for x in xSet for y in ySet] 

дорівнює

result=[] 
for x in xSet:
  for y in ySet: 
    result.append(exp1)

тоді як,

[[exp1 for x in xSet] for y in ySet]

дорівнює

result=[]
for y in ySet:
  innerResult=[]
  for x in xSet:
    innerResult.append(exp1)
  result.append(innerResult)

Я задав подібне запитання щодо еквівалента для виразу циклу для розуміння складного списку.
Наведені там відповіді реконструюють форму, зрозумівши, що вона робить внутрішньо.
Я хотів би знати, як це працює систематично, щоб я міг застосувати цю концепцію до інших дещо різних прикладів.


3
Примітка сторони: У вашому прикладі, ви могли б транспонувати рядки в стовпці з допомогою cols = zip(*rows), після чого ви могли б просто використовувати min(col)і max(col)для кожного стовпця: [(min(c), max(c)) for c in cols]. Або в одній короткій лінії: [(min(c), max(c)) for col in zip(*rows)].
taleinat

Чи було б це правдою та покращило б ясність, якби ви писали exp1 (x, y) замість просто exp1? Я думаю, це мається на увазі, але хотіли б бути впевнені?
GreenAsJade

@GreenAsJade ну, так, це спрацювало б, exp1 мав бути виразом1
Євген

Відповіді:


74

Коротка відповідь: так, ви правильно розумієте .

Є лише підводка: спосіб, яким ви зазвичай використовуєте розуміння вкладеного списку в коді python, - це робота з багатовимірними масивами.

Типовий приклад, коли ви оперуєте матрицями:

>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [[el - 1 for el in row] for row in matrix]
[[0, 1, 2], [3, 4, 5], [6, 7, 8]]

Як бачите, "вкладання" працює, оперуючи кожним виміром матриці.

У наведених вами прикладах здається, що ySet[невдале ім'я btw, оскільки набори є одним із типів, що надаються з python], - це просто загальний лічильник, який ускладнює відстеження того, що відбувається під капотом.

Що стосується вашого першого прикладу:

>>> rows = ([1, 2, 3], [10, 20, 30])
>>> [(min([row[i] for row in rows]),max([row[i] for row in rows])) for i in range(len(rows[0]))]
[(1, 10), (2, 20), (3, 30)]

Можливо, ви захочете розглянути вбудовану функцію zip :

>>> zip(rows[0], rows[1])
[(1, 10), (2, 20), (3, 30)]

або для максимальної стислості та елегантності:

>>> zip(*rows)
[(1, 10), (2, 20), (3, 30)]

HTH!


76

Справді, ти маєш рацію. Це докладно описано у розділі Вирази у Довідковій мові Python .

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

>>> matrix = [[1, 2], [3, 4]]
>>> [item for item in row for row in matrix] # oops!
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    [item for item in row for row in matrix]
NameError: name 'row' is not defined
>>> [item for row in matrix for item in row] # nesting is in left-to-right order
[1, 2, 3, 4]

Я подивився посилання. Дійсно, є пояснення для [елемент для рядка в матриці для елемента в рядку], але не вдалося знайти пояснення для формату [[exp для елемента в рядку] для рядка в матриці]. Мені щось не вистачає з перерахованої там граматики?
Євген

Ви нічого не пропускаєте, але це тому, що ваш приклад не використовує більше жодної спеціальної граматики, це лише два простих розуміння списку! Перший [exp for item in row]створить список із заданим рядком. Розуміння "зовнішнього" списку створить список, у якому кожен елемент - це список, створений "внутрішнім" списком-комп, по одному для кожного рядка в матриці.
taleinat

1
О Як ви вказали у своїй відповіді, порядок важливий. І, мені було цікаво, чи є розділ про бібліотечні посилання, в якому йдеться про впорядкування формату [[розуміння списку] розуміння списку]].
Євген

3
Немає такого розділу в документації, про який я знаю. Причина полягає в тому, що в розумінні списку виразом, що обчислюється для кожного елемента, може бути будь-який дійсний вираз Python. У цьому контексті розуміння "внутрішнього" списку подібно до будь-якого іншого виразу Python.
taleinat

2
ваууууу .. я єдиний здивований цим впорядкуванням: тепер пояснення, чому рівень макросів (матриця в даному випадку ..) виникає перед вкладеним / мікрорівнем (рівень рядків ..) може бути в порядку ..
StephenBoesch
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.