Syntax hinter sortiert (Schlüssel = Lambda:…)

152

Ich verstehe die Syntax hinter dem sorted()Argument nicht ganz :

key=lambda variable: variable[0]

Ist nicht lambdawillkürlich? Warum wird variablezweimal angegeben, was wie ein aussieht dict?

Christopher Markieta
quelle

Antworten:

162

keyist eine Funktion, die aufgerufen wird, um die Elemente der Sammlung zu transformieren, bevor sie verglichen werden. Der an übergebene Parameter keymuss aufrufbar sein.

Die Verwendung von lambdaerstellt eine anonyme Funktion (die aufrufbar ist). Im Falle des sortedaufrufbaren nimmt nur ein Parameter. Pythons lambdaist ziemlich einfach. Es kann nur eines wirklich tun und zurückgeben.

Die Syntax von lambdaist das Wort, lambdagefolgt von der Liste der Parameternamen und einem einzelnen Codeblock. Die Parameterliste und der Codeblock werden durch Doppelpunkte abgegrenzt. Dies ist vergleichbar mit anderen Konstrukten in Python ebenso wie while, for, ifund so weiter. Dies sind alles Anweisungen, die normalerweise einen Codeblock haben. Lambda ist nur eine weitere Instanz einer Anweisung mit einem Codeblock.

Wir können die Verwendung von Lambda mit der von def vergleichen, um eine Funktion zu erstellen.

adder_lambda = lambda parameter1,parameter2: parameter1+parameter2
def adder_regular(parameter1, parameter2): return parameter1+parameter2

Lambda gibt uns nur eine Möglichkeit, dies zu tun, ohne einen Namen zu vergeben. Das macht es großartig für die Verwendung als Parameter für eine Funktion.

variable wird hier zweimal verwendet, weil es auf der linken Seite des Doppelpunkts der Name eines Parameters ist und auf der rechten Seite im Codeblock verwendet wird, um etwas zu berechnen.

Evan
quelle
10
Hinweis (zu OP): Es sollte vermieden werden, einem Namen ein Lambda zuzuweisen (dh es auf eine andere Weise als als anonyme Funktion zu verwenden). Wenn Sie dies tun, sollten Sie wahrscheinlich nur a verwenden def.
wim
151

Ich denke, alle Antworten hier decken den Kern dessen ab, was die Lambda-Funktion im Kontext von sorted () recht gut macht, aber ich habe immer noch das Gefühl, dass eine Beschreibung fehlt, die zu einem intuitiven Verständnis führt, also hier sind meine zwei Cent.

Der Vollständigkeit halber werde ich im Vorfeld das Offensichtliche darlegen: sorted () gibt eine Liste sortierter Elemente zurück und ob wir auf eine bestimmte Weise sortieren möchten oder wenn wir eine komplexe Liste von Elementen sortieren möchten (z. B. verschachtelte Listen oder eine Liste von Tupeln) können wir das Schlüsselargument aufrufen.

Für mich besteht das intuitive Verständnis des Hauptarguments, warum es aufrufbar sein muss, und die Verwendung von Lambda als (anonyme) aufrufbare Funktion, um dies zu erreichen, aus zwei Teilen.

  1. Die Verwendung von lamba bedeutet letztendlich, dass Sie nicht eine ganze Funktion schreiben (definieren) müssen, wie die, für die sblom ein Beispiel bereitgestellt hat. Lambda-Funktionen werden erstellt, verwendet und sofort zerstört. Sie funken Ihren Code also nicht mit mehr Code auf, der nur einmal verwendet wird. Dies ist, wie ich es verstehe, der Kernnutzen der Lambda-Funktion, und ihre Anwendungen für solche Rollen sind breit gefächert. Seine Syntax ist rein konventionell, was im Wesentlichen der Natur der programmatischen Syntax im Allgemeinen entspricht. Lernen Sie die Syntax und fertig.

Die Lambda-Syntax lautet wie folgt:

lambda input_variable (s) : leckerer liner

z.B

In [1]: f00 = lambda x: x/2

In [2]: f00(10)
Out[2]: 5.0

In [3]: (lambda x: x/2)(10)
Out[3]: 5.0

In [4]: (lambda x, y: x / y)(10, 2)
Out[4]: 5.0

In [5]: (lambda: 'amazing lambda')() # func with no args!
Out[5]: 'amazing lambda'
  1. Die Idee hinter dem keyArgument ist, dass es eine Reihe von Anweisungen aufnehmen sollte, die im Wesentlichen die Funktion 'sortiert ()' auf die Listenelemente verweisen, nach denen sortiert werden soll. Wenn es heißt key=, bedeutet es wirklich: Wenn ich die Liste Element für Element durchlaufe (dh für e in Liste), übergebe ich das aktuelle Element an die Funktion, die ich im Schlüsselargument angegeben habe, und verwende diese um eine transformierte Liste zu erstellen, die mich über die Reihenfolge der endgültig sortierten Liste informiert.

Hör zu:

mylist = [3,6,3,2,4,8,23]
sorted(mylist, key=WhatToSortBy)

Basisbeispiel:

sorted(mylist)

[2, 3, 3, 4, 6, 8, 23] # Alle Zahlen sind in der Reihenfolge von klein bis groß.

Beispiel 1:

mylist = [3,6,3,2,4,8,23]
sorted(mylist, key=lambda x: x%2==0)

[3, 3, 23, 6, 2, 4, 8] # Ist dieses sortierte Ergebnis für Sie intuitiv sinnvoll?

Beachten Sie, dass meine Lambda-Funktion sorted angewiesen hat, vor dem Sortieren zu prüfen, ob (e) gerade oder ungerade ist.

ABER WARTE! Sie könnten (oder sollten vielleicht) sich zwei Dinge fragen - erstens, warum kommen meine Chancen vor meinen Abend (da mein Schlüsselwert meiner sortierten Funktion zu sagen scheint, dass sie Abend mit dem Mod-Operator in priorisieren soll x%2==0). Zweitens, warum sind meine Abende nicht in Ordnung? 2 kommt vor 6 richtig? Durch die Analyse dieses Ergebnisses erfahren wir etwas tieferes über die Funktionsweise des sortierten () 'Schlüssel'-Arguments, insbesondere in Verbindung mit der anonymen Lambda-Funktion.

Erstens werden Sie feststellen, dass die Chancen zwar vor den Abenden liegen, die Abenden selbst jedoch nicht sortiert sind. Warum ist das?? Lesen wir die Dokumente :

Schlüsselfunktionen Ab Python 2.4 haben sowohl list.sort () als auch sorted () einen Schlüsselparameter hinzugefügt, um eine Funktion anzugeben, die für jedes Listenelement aufgerufen werden soll, bevor Vergleiche durchgeführt werden.

Wir müssen hier ein wenig zwischen den Zeilen lesen, aber dies sagt uns, dass die Sortierfunktion nur einmal aufgerufen wird. Wenn wir das Schlüsselargument angeben, sortieren wir nach dem Wert, auf den die Schlüsselfunktion zeigt.

Was bringt das Beispiel mit einem Modulo zurück? Ein boolescher Wert: True == 1, False == 0. Wie geht sortiert mit diesem Schlüssel um? Grundsätzlich wird die ursprüngliche Liste in eine Folge von Einsen und Nullen umgewandelt.

[3,6,3,2,4,8,23] wird zu [0,1,0,1,1,1,0]

Jetzt kommen wir irgendwohin. Was bekommen Sie, wenn Sie die transformierte Liste sortieren?

[0,0,0,1,1,1,1]

Okay, jetzt wissen wir, warum die Chancen vor dem Abend stehen. Aber die nächste Frage ist: Warum kommt die 6 in meiner endgültigen Liste immer noch vor die 2? Nun, das ist einfach - es liegt daran, dass das Sortieren nur einmal erfolgt! dh diese Einsen repräsentieren immer noch die ursprünglichen Listenwerte, die sich an ihren ursprünglichen Positionen relativ zueinander befinden. Da die Sortierung nur einmal erfolgt und wir keine Sortierfunktion aufrufen, um die ursprünglichen geraden Werte von niedrig nach hoch zu ordnen, bleiben diese Werte in ihrer ursprünglichen Reihenfolge relativ zueinander.

Die letzte Frage lautet dann: Wie denke ich konzeptionell darüber nach, wie die Reihenfolge meiner Booleschen Werte beim Ausdrucken der endgültigen sortierten Liste wieder in die ursprünglichen Werte umgewandelt wird?

Sorted () ist eine integrierte Methode, die (lustige Tatsache) einen hybriden Sortieralgorithmus namens Timsort verwendetdas kombiniert Aspekte der Zusammenführungssortierung und der Einfügesortierung. Mir scheint klar, dass es einen Mechaniker gibt, der diese Werte speichert und sie mit ihrer booleschen Identität (Maske) bündelt, die durch (...!) Die Lambda-Funktion bestimmt wird. Die Reihenfolge wird durch ihre boolesche Identität bestimmt, die aus der Lambda-Funktion berechnet wird. Beachten Sie jedoch, dass diese Unterlisten (von Einsen und Nullen) selbst nicht nach ihren ursprünglichen Werten sortiert sind. Daher ist die endgültige Liste, obwohl sie nach Odds and Evens organisiert ist, nicht nach Unterlisten sortiert (die Evens sind in diesem Fall nicht in Ordnung). Die Tatsache, dass die Quoten geordnet sind, liegt daran, dass sie in der ursprünglichen Liste zufällig bereits in Ordnung waren. Die Konsequenz daraus ist, dass bei der Transformation von Lambda die ursprüngliche Reihenfolge der Unterlisten beibehalten wird.

Wie hängt das alles mit der ursprünglichen Frage zusammen und vor allem mit unserer Intuition, wie wir sorted () mit seinem Hauptargument und Lambda implementieren sollten?

Diese Lambda-Funktion kann als Zeiger betrachtet werden, der auf die Werte zeigt, nach denen sortiert werden muss, unabhängig davon, ob es sich um einen Zeiger handelt, der einen Wert auf seinen durch die Lambda-Funktion transformierten Booleschen Wert abbildet, oder ob es sich um ein bestimmtes Element in einer verschachtelten Liste handelt, Tupel, Dikt usw., wiederum bestimmt durch die Lambda-Funktion.

Versuchen wir vorherzusagen, was passiert, wenn ich den folgenden Code ausführe.

mylist = [(3, 5, 8), (6, 2, 8), ( 2, 9, 4), (6, 8, 5)]
sorted(mylist, key=lambda x: x[1])

Mein sortedAnruf sagt offensichtlich: "Bitte sortieren Sie diese Liste". Das Hauptargument macht dies etwas spezifischer, indem es sagt, dass für jedes Element (x) in meiner Liste der Index 1 dieses Elements zurückgegeben wird und dann alle Elemente der ursprünglichen Liste 'mylist' nach der sortierten Reihenfolge der von berechneten Liste sortiert werden die Lambda-Funktion. Da wir eine Liste von Tupeln haben, können wir ein indiziertes Element von diesem Tupel zurückgeben. So bekommen wir:

[(6, 2, 8), (3, 5, 8), (6, 8, 5), (2, 9, 4)]

Führen Sie diesen Code aus, und Sie werden feststellen, dass dies die Reihenfolge ist. Wenn Sie versuchen, eine Liste von Ganzzahlen zu indizieren, werden Sie feststellen, dass der Code fehlerhaft ist.

Dies war eine langwierige Erklärung, aber ich hoffe, dies hilft Ihnen dabei, Ihre Intuition über die Verwendung von Lambda-Funktionen als Hauptargument in sorted () und darüber hinaus zu sortieren.

PaulG
quelle
8
ausgezeichnete und umfassende Erklärung. Diese Antwort verdient 100 Punkte. Aber ich frage mich, warum diese Antwort weniger gefällt.
javed
3
Vielen Dank für die tiefe Erklärung. Ich habe die Dokumente gelesen und die Anleitungen sortiert, und mir war die Idee hinter der keyFunktion nicht klar . Wenn Sie versuchen, die sortedFunktion zu verstehen , wird die lambdaSyntax nur zum Verständnis.
Sanbor
3
Dies ist die beste Erklärung hier. Dies war sehr nützlich, um zu verstehen, wie dies tatsächlich funktionierte. Ich habe die Lambda-Funktion irgendwie verstanden, aber es machte keinen Sinn, sie im Kontext von sorted () zu verwenden. Das hat wirklich geholfen, danke!
TGWaffles
2
Dies ist eine brillante Antwort. Grüße Sie, Sir.
Rajesh Mappu
2
Dies ist eine meiner Lieblingsantworten zum Stapelüberlauf. Danke dir!
AdR
26

lambdaist ein Python-Schlüsselwort, mit dem anonyme Funktionen generiert werden .

>>> (lambda x: x+2)(3)
5
Ignacio Vazquez-Abrams
quelle
2
Warum gibt es jeweils Klammern?
Christopher Markieta
19
Die Parens sind 3da, weil sie an eine Funktion übergeben werden. Die Parens befinden sich um das Lambda herum, sodass der Ausdruck nicht als analysiert wird lambda x: x+2(3), was ungültig ist, da 2es sich nicht um eine Funktion handelt.
Ignacio Vazquez-Abrams
Ich bin mir nicht sicher, ob mir der Begriff "anonyme" Funktionen gefällt. Ich meine, es ist wahr, dass sie nicht benannt sind, also anonym ist "technisch" korrekt. Ich würde sie lieber als "temporäre Funktionen" bezeichnen. Aber dann bin ich ein Pedant.
user5179531
12

Die variablelinks von dem :ist ein Parametername. Bei Verwendung von variablerechts wird der Parameter verwendet.

Bedeutet fast genau das Gleiche wie:

def some_method(variable):
  return variable[0]
sblom
quelle
5

Ein weiteres Beispiel für die Verwendung der Funktion sorted () mit key = lambda. Angenommen, Sie haben eine Liste mit Tupeln. In jedem Tupel haben Sie eine Marke, ein Modell und ein Gewicht des Autos und Sie möchten diese Liste der Tupel nach Marke, Modell oder Gewicht sortieren. Sie können es mit Lambda tun.

cars = [('citroen', 'xsara', 1100), ('lincoln', 'navigator', 2000), ('bmw', 'x5', 1700)]

print(sorted(cars, key=lambda car: car[0]))
print(sorted(cars, key=lambda car: car[1]))
print(sorted(cars, key=lambda car: car[2]))

Ergebnisse:

[('bmw', 'x5', '1700'), ('citroen', 'xsara', 1100), ('lincoln', 'navigator', 2000)]
[('lincoln', 'navigator', 2000), ('bmw', 'x5', '1700'), ('citroen', 'xsara', 1100)]
[('citroen', 'xsara', 1100), ('bmw', 'x5', 1700), ('lincoln', 'navigator', 2000)]
Füller36
quelle
3

lambdaist eine anonyme Funktion, keine willkürliche Funktion. Der Parameter, der akzeptiert wird, ist die Variable, mit der Sie arbeiten, und die Spalte, in der Sie sie sortieren.

Makoto
quelle
1

Nur um es neu zu formulieren, erwartet der Schlüssel (Optional. Eine Funktion, die ausgeführt werden muss, um die Reihenfolge zu bestimmen. Standard ist Keine) in sortierten Funktionen eine Funktion und Sie verwenden Lambda.

Um Lambda zu definieren, geben Sie die Objekteigenschaft an, die Sie sortieren möchten, und die integrierte Sortierfunktion von Python kümmert sich automatisch darum.

Wenn Sie nach mehreren Eigenschaften sortieren möchten, weisen Sie key = lambda x: (property1, property2) zu.

Um die Reihenfolge anzugeben, übergeben Sie reverse = true als drittes Argument (optional. Ein Boolescher Wert. False sortiert aufsteigend, True sortiert absteigend. Standard ist False) der sortierten Funktion.

kta
quelle
1

Einfache und nicht zeitaufwändige Antwort mit einem Beispiel für die gestellte Frage Folgen Sie diesem Beispiel:

 user = [{"name": "Dough", "age": 55}, 
            {"name": "Ben", "age": 44}, 
            {"name": "Citrus", "age": 33},
            {"name": "Abdullah", "age":22},
            ]
    print(sorted(user, key=lambda el: el["name"]))
    print(sorted(user, key= lambda y: y["age"]))

Schauen Sie sich die Namen in der Liste an, sie beginnen mit D, B, C und A. Und wenn Sie das Alter bemerken, sind sie 55, 44, 33 und 22. Der erste Druckcode

print(sorted(user, key=lambda el: el["name"]))

Ergebnisse an:

[{'name': 'Abdullah', 'age': 22}, 
{'name': 'Ben', 'age': 44}, 
{'name': 'Citrus', 'age': 33}, 
{'name': 'Dough', 'age': 55}]

sortiert den Namen, weil wir nach key = lambda el: el ["name"] die Namen sortieren und die Namen in alphabetischer Reihenfolge zurückgeben.

Der zweite Druckcode

print(sorted(user, key= lambda y: y["age"]))

Ergebnis:

[{'name': 'Abdullah', 'age': 22},
 {'name': 'Citrus', 'age': 33},
 {'name': 'Ben', 'age': 44}, 
 {'name': 'Dough', 'age': 55}]

sortiert nach Alter, und daher kehrt die Liste in aufsteigender Reihenfolge des Alters zurück.

Versuchen Sie diesen Code zum besseren Verständnis.

AbdullahS96
quelle