Sintassi dietro ordinata (chiave = lambda: ...)


152

Non capisco bene la sintassi dietro l' sorted()argomento:

key=lambda variable: variable[0]

Non è lambdaarbitrario? Perché è variableindicato due volte in quello che sembra un dict?

Risposte:


163

keyè una funzione che verrà chiamata per trasformare gli oggetti della collezione prima che vengano confrontati. Il parametro passato a keydeve essere qualcosa che è richiamabile.

L'uso di lambdacrea una funzione anonima (che è richiamabile). Nel caso del sortedcallable accetta solo un parametro. Python's lambdaè piuttosto semplice. Può solo fare e restituire davvero una cosa.

La sintassi di lambdaè la parola lambdaseguita dall'elenco dei nomi dei parametri quindi da un singolo blocco di codice. L'elenco dei parametri e il blocco di codice sono delineati dai due punti. Questo è simile ad altri costrutti in pitone così come while, for, ife così via. Sono tutte istruzioni che in genere hanno un blocco di codice. Lambda è solo un'altra istanza di un'istruzione con un blocco di codice.

Possiamo confrontare l'uso di lambda con quello di def per creare una funzione.

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

lambda ci dà solo un modo per farlo senza assegnare un nome. Il che lo rende ideale per l'utilizzo come parametro di una funzione.

variable viene usato due volte qui perché sulla sinistra dei due punti è il nome di un parametro e sulla destra viene utilizzato nel blocco di codice per calcolare qualcosa.


10
nota (a OP): dovrebbe essere evitato di assegnare un lambda a un nome (cioè usandolo in un modo diverso da come funzione anonima). se ti ritrovi a fare questo, probabilmente dovresti semplicemente usare a def.
mercoledì

151

Penso che tutte le risposte qui coprano il nucleo di ciò che la funzione lambda fa nel contesto di sort () abbastanza bene, tuttavia mi sento ancora come se mancasse una descrizione che porta a una comprensione intuitiva, quindi ecco i miei due centesimi.

Per completezza, indicherò l'evidente in primo piano: sort () restituisce un elenco di elementi ordinati e se vogliamo ordinare in un modo particolare o se vogliamo ordinare un elenco complesso di elementi (ad esempio elenchi nidificati o un elenco di tuple) possiamo invocare l'argomento chiave.

Per me, la comprensione intuitiva dell'argomento chiave, il motivo per cui deve essere richiamabile e l'uso di lambda come funzione (anonima) richiamabile per ottenere questo risultato si divide in due parti.

  1. L'uso di lamba alla fine significa che non devi scrivere (definire) un'intera funzione, come quella che sblom ha fornito un esempio di. Le funzioni Lambda vengono create, utilizzate e immediatamente distrutte, in modo tale da non ritoccare il codice con più codice che verrà utilizzato una sola volta. Questo, a quanto ho capito, è l'utilità principale della funzione lambda e le sue applicazioni per tali ruoli sono ampie. La sua sintassi è puramente per convenzione, che è essenzialmente la natura della sintassi programmatica in generale. Impara la sintassi e falla finita.

La sintassi Lambda è la seguente:

lambda input_variable (s) : gustoso one liner

per esempio

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. L'idea alla base keydell'argomento è che dovrebbe includere una serie di istruzioni che indicheranno essenzialmente la funzione 'sort ()' su quegli elementi della lista che dovrebbero essere usati per ordinare. Quando dice key=, ciò che significa in realtà è: mentre eseguo iterando l'elenco un elemento alla volta (cioè per e in list), passerò l'elemento corrente alla funzione che fornisco nell'argomento chiave e lo uso per creare un elenco trasformato che mi informerà sull'ordine dell'elenco ordinato finale.

Controlla:

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

Esempio di base:

sorted(mylist)

[2, 3, 3, 4, 6, 8, 23] # tutti i numeri sono in ordine da piccolo a grande.

Esempio 1:

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

[3, 3, 23, 6, 2, 4, 8] # Questo risultato ordinato ha un senso intuitivo per te?

Si noti che la mia funzione lambda ha detto a ordinati per verificare se (e) era pari o dispari prima dell'ordinamento.

MA ASPETTA! Potresti (o forse dovresti) chiederti due cose: in primo luogo, perché le mie probabilità vengono prima dei miei pari (dal momento che il mio valore chiave sembra dire alla mia funzione ordinata di dare la priorità ai pari usando l'operatore mod in x%2==0). Secondo, perché i miei pari sono fuori servizio? 2 viene prima di 6 giusto? Analizzando questo risultato, impareremo qualcosa di più approfondito su come funziona l'argomento ordinato () 'chiave', specialmente in combinazione con la funzione lambda anonima.

In primo luogo, noterai che mentre le probabilità vengono prima dei pari, i pari stessi non vengono ordinati. Perchè è questo?? Consente di leggere i documenti :

Funzioni chiave A partire da Python 2.4, sia list.sort () che sort () hanno aggiunto un parametro chiave per specificare una funzione da chiamare su ciascun elemento della lista prima di effettuare i confronti.

Dobbiamo fare un po 'di lettura tra le righe qui, ma ciò che ci dice è che la funzione di ordinamento viene chiamata solo una volta, e se specificiamo l'argomento chiave, allora ordiniamo per il valore a cui punta la funzione chiave.

Quindi cosa restituisce l'esempio usando un modulo? Un valore booleano: True == 1, False == 0. Quindi, come funziona l'ordinamento con questa chiave? Trasforma sostanzialmente l'elenco originale in una sequenza di 1 e 0 secondi.

[3,6,3,2,4,8,23] diventa [0,1,0,1,1,1,0]

Ora stiamo arrivando da qualche parte. Cosa ottieni quando ordini l'elenco trasformato?

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

Va bene, quindi ora sappiamo perché le probabilità arrivano prima dei pari. Ma la domanda successiva è: perché il 6 viene ancora prima del 2 nella mia lista finale? Bene, è facile - è perché l'ordinamento avviene solo una volta! cioè Quelli 1 rappresentano ancora i valori della lista originale, che sono nelle loro posizioni originali l'uno rispetto all'altro. Poiché l'ordinamento avviene una sola volta e non chiamiamo alcun tipo di funzione di ordinamento per ordinare i valori pari originali dal più basso al più alto, tali valori rimangono nel loro ordine originale l'uno rispetto all'altro.

La domanda finale è quindi questa: come posso pensare concettualmente a come l'ordine dei miei valori booleani viene ricondotto ai valori originali quando stampo l'elenco ordinato finale?

Sorted () è un metodo integrato che (fatto divertente) utilizza un algoritmo di ordinamento ibrido chiamato Timsortche combina aspetti di tipo di unione e ordinamento per inserzione. Mi sembra chiaro che quando lo chiami, c'è un meccanico che tiene in memoria questi valori e li raggruppa con la loro identità booleana (maschera) determinata dalla (...!) Funzione lambda. L'ordine è determinato dalla loro identità booleana calcolata dalla funzione lambda, ma tieni presente che queste liste secondarie (di uno e di zeri) non sono esse stesse ordinate in base ai loro valori originali. Quindi, l'elenco finale, sebbene organizzato da Odds e Evens, non è ordinato in base alla sublist (in questo caso i pari sono fuori servizio). Il fatto che le probabilità siano ordinate è perché erano già in ordine per coincidenza nell'elenco originale. L'aspetto da asporto di tutto ciò è che quando lambda esegue quella trasformazione, l'ordine originale delle liste secondarie viene mantenuto.

Quindi, in che modo tutto ciò si ricollega alla domanda originale e, soprattutto, alla nostra intuizione su come dovremmo implementare sort () con il suo argomento chiave e lambda?

Quella funzione lambda può essere pensata come un puntatore che punta ai valori che dobbiamo ordinare, sia che si tratti di un puntatore che mappa un valore al suo booleano trasformato dalla funzione lambda, sia che sia un elemento particolare in un elenco nidificato, tupla, dict, ecc., ancora una volta determinato dalla funzione lambda.

Proviamo a prevedere cosa succede quando eseguo il seguente codice.

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

La mia sortedchiamata ovviamente dice "Per favore ordina questo elenco". L'argomento chiave lo rende un po 'più specifico dicendo, per ogni elemento (x) in mylist, restituire l'indice 1 di quell'elemento, quindi ordinare tutti gli elementi dell'elenco originale' mylist 'in base all'ordine ordinato dell'elenco calcolato da la funzione lambda. Poiché abbiamo un elenco di tuple, possiamo restituire un elemento indicizzato da quella tupla. Quindi otteniamo:

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

Esegui quel codice e scoprirai che questo è l'ordine. Prova a indicizzare un elenco di numeri interi e scoprirai che il codice si rompe.

Questa è stata una spiegazione lunga, ma spero che questo aiuti a "ordinare" la tua intuizione sull'uso delle funzioni lambda come argomento chiave in sort () e oltre.


8
spiegazione eccellente e completa. Questa risposta merita 100 punti. Ma mi chiedo perché i mi piace siano meno di questa risposta.
javed

3
Grazie per la profonda spiegazione. Ho letto i documenti e l'ordinamento how-to e non mi era chiaro l'idea alla base della keyfunzione. Se stai cercando di capire la sortedfunzione, la lambdasintassi si limita a capire.
sanbor

3
Questa è la migliore spiegazione qui. Questo è stato davvero utile per aiutarmi a capire come funzionava davvero - ho capito bene la funzione lambda, ma usarla nel contesto di sort () non aveva senso. Questo mi ha davvero aiutato, grazie!
TGWaffles,

2
Questa è una risposta brillante. Salutate signore.
Rajesh Mappu,

2
Questa è una delle mie risposte preferite sullo overflow dello stack. Grazie!
AdR

26

lambdaè una parola chiave Python utilizzata per generare funzioni anonime .

>>> (lambda x: x+2)(3)
5

2
Perché ci sono parentesi intorno a ciascuna?
Christopher Markieta,

19
I genitori sono in giro 3perché viene passato a una funzione. Le parentesi sono attorno alla lambda in modo che l'espressione non venga analizzata lambda x: x+2(3), il che non è valido poiché 2non è una funzione.
Ignacio Vazquez-Abrams,

Non sono sicuro di apprezzare il termine funzioni "anonime". Voglio dire, è vero che non hanno un nome, quindi anonimo è "tecnicamente" accurato. Preferirei chiamarli "funzioni temporanee". Ma poi sono un pedante.
user5179531

12

La variablesinistra di :è un nome di parametro. L'uso di variablea destra sta facendo uso del parametro.

Significa quasi esattamente lo stesso di:

def some_method(variable):
  return variable[0]

5

Un altro esempio di utilizzo dell'ordinamento () funzione con key = lambda. Consideriamo che hai un elenco di tuple. In ogni tupla hai una marca, un modello e un peso dell'auto e vuoi ordinare questo elenco di tuple per marca, modello o peso. Puoi farlo con lambda.

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

risultati:

[('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)]

3

lambdaè una funzione anonima, non una funzione arbitraria. Il parametro accettato sarebbe la variabile con cui stai lavorando e la colonna in cui lo stai ordinando.



1

Solo per riformulare, il tasto (Opzionale. Una funzione da eseguire per decidere l'ordine. L'impostazione predefinita è Nessuno) nelle funzioni ordinate si aspetta una funzione e si utilizza lambda.

Per definire lambda, si specifica la proprietà dell'oggetto che si desidera ordinare e la funzione ordinata integrata di Python se ne occuperà automaticamente.

Se si desidera ordinare in base a più proprietà, assegnare key = lambda x: (proprietà1, proprietà2).

Per specificare l'ordinamento, passare reverse = true come terzo argomento (Facoltativo. Un valore booleano. False ordinerà in ordine crescente, True ordinerà in ordine decrescente. L'impostazione predefinita è False) della funzione ordinata.


1

Risposta semplice e non dispendiosa in termini di tempo con un esempio pertinente alla domanda posta Seguire questo esempio:

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

Guarda i nomi nell'elenco, iniziano con D, B, C e A. E se noti le età, sono 55, 44, 33 e 22. Il primo codice di stampa

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

Risultati a:

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

ordina il nome, perché con key = lambda el: el ["name"] stiamo ordinando i nomi e i nomi ritornano in ordine alfabetico.

Il secondo codice di stampa

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

Risultato:

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

ordina per età, e quindi l'elenco ritorna in ordine crescente di età.

Prova questo codice per una migliore comprensione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.