Grundlegendes zum Verständnis verschachtelter Listen

74

Ich möchte das Verständnis verschachtelter Listen verstehen. Unten habe ich einen Listenverständnisausdruck und deren for-Schleifenäquivalent aufgelistet.
Ich frage mich, ob mein Verständnis bei diesen richtig ist.

Zum Beispiel,

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

ist äquivalent zu

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)

Wenn ich verallgemeinern darf, denke ich

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

Form kann wie folgt übersetzt werden. (Ich hoffe, ich habe Recht damit)

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

Für einen einfacheren Fall

[exp1 for x in xSet for y in ySet] 

entspricht

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

wohingegen,

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

entspricht

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

Ich habe eine ähnliche Frage zu Äquivalent für Schleifenausdruck für komplexes Listenverständnis gestellt.
Die dort gegebenen Antworten rekonstruieren die Form, nachdem sie verstanden haben, was sie intern tut.
Ich möchte wissen, wie es systematisch funktioniert, damit ich das Konzept auf andere leicht unterschiedliche Beispiele anwenden kann.

Eugen
quelle
3
Randnotiz: In Ihrem Beispiel hätten Sie die Zeilen in Spalten umsetzen können, indem cols = zip(*rows)Sie einfach min(col)und max(col)für jede Spalte Folgendes verwendet hätten : [(min(c), max(c)) for c in cols]. Oder in einer kurzen Zeile : [(min(c), max(c)) for col in zip(*rows)].
Taleinat
Wäre es wahr und würde die Klarheit verbessern, wenn Sie exp1 (x, y) anstatt nur exp1 schreiben würden? Ich denke, es ist impliziert, möchte aber sicher sein?
GreenAsJade
@ GreenAsJade gut, ja das würde funktionieren, exp1 sollte expression1 sein
eugene

Antworten:

74

Die kurze Antwort lautet: Ja, Sie haben Verständnis .

Es gibt nur einen Haken: Die Art und Weise, wie Sie normalerweise das Verständnis verschachtelter Listen in Python-Code verwenden, besteht darin, mehrdimensionale Arrays zu bearbeiten.

Ein typisches Beispiel ist, wenn Sie mit Matrizen arbeiten:

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

Wie Sie sehen können, funktioniert das "Verschachteln", indem jede Dimension der Matrix bearbeitet wird.

In den von Ihnen bereitgestellten Beispielen scheint es, dass ySet[übrigens ein unglücklicher Name, da Sets einer der mit Python bereitgestellten Typen sind] nur ein generischer Zähler ist, was es etwas schwieriger macht, zu verfolgen, was unter der Haube vor sich geht.

Wie für Ihr erstes Beispiel:

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

Vielleicht möchten Sie sich die integrierte Funktion von zip ansehen :

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

oder für maximale Kürze und Eleganz:

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

HTH!

Mac
quelle
76

In der Tat sind Sie richtig. Dies wird ausführlich im Abschnitt Ausdrücke in der Python-Sprachreferenz beschrieben .

Beachten Sie insbesondere die Reihenfolge der Verschachtelung mehrerer fors in einem einzigen Listenverständnis, das immer von links nach rechts erfolgt:

>>> 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]
Taleinat
quelle
Ich habe mir den Link angesehen. Es gibt zwar eine Erklärung für das Format [Element für Zeile in Matrix für Element in Zeile], konnte jedoch keine Erklärung für das Format [[Exp für Element in Zeile] für Zeile in Matrix] finden. Vermisse ich etwas in der dort aufgeführten Grammatik?
Eugene
Sie vermissen nichts, aber das liegt daran, dass Ihr Beispiel keine spezielle Grammatik verwendet, sondern nur zwei einfache Listenverständnisse! Der erste [exp for item in row]erstellt eine Liste mit einer bestimmten Zeile. Das "äußere" Listenverständnis erstellt eine Liste, in der jedes Element eine Liste ist, die von der "inneren" Listenkomposition erstellt wurde, eine für jede Zeile in der Matrix.
Taleinat
1
Oh. Wie Sie in Ihrer Antwort betont haben, ist die Reihenfolge wichtig. Und ich habe mich gefragt, ob es einen Abschnitt über Bibliotheksreferenzen gibt, in dem es um die Reihenfolge des Listenverständnisses geht.
Eugene
3
Es gibt keinen solchen Abschnitt in den Dokumenten, von denen ich weiß. Der Grund dafür ist, dass in einem Listenverständnis der für jedes Element ausgewertete Ausdruck ein beliebiger gültiger Python-Ausdruck sein kann. In diesem Zusammenhang ist ein "inneres" Listenverständnis wie jeder andere Python-Ausdruck.
Taleinat
2
wow whee .. bin ich der einzige, der von dieser Reihenfolge überrascht ist: jetzt eine Erklärung, warum die Makroebene (in diesem Fall Matrix ..) auftritt, bevor die verschachtelte / Mikroebene (
Zeilenebene