
In Python, l’ordinamento di un elenco di dizionari con il metodo sort() o la funzione sorted() genera l’errore TypeError per il metodo predefinito.
Specificando il parametro chiave di sort() o sorted(), è possibile ordinare un elenco di dizionari in base al valore della chiave specifica.
In questo articolo vengono descritti i seguenti contenuti.
- L’ordinamento di un elenco di dizionari generi un errore per un elenco predefinito
- Specificare le espressioni lambda per il parametro chiave
- Specificare operator.mgetter() per il parametro chiave
- Ordina per più chiavi
- max(), min() per un elenco di dizionari
I codici di esempio seguenti utilizzano un elenco di dizionari con chiavi comuni. Il modulo pprint utilizzatore viene per semplificare la lettura dell’output.
import pprint
l = [{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20},
{'Name': 'Charlie', 'Age': 30, 'Point': 70}]
L’ordinamento di un elenco di dizionari generi un errore per un elenco predefinito
L’ordinamento di un elenco di dizionari (dict) con il metodo sort() o la funzione sorted() generale l’errore TypeError per la direttiva predefinita.
Questo perché il dizionario non supporta i confronti con <, >, ecc.
# sorted(l)
# TypeError: '<' not supported between instances of 'dict' and 'dict'
Specificare le espressioni lambda per il parametro chiave
Per ordinare un elenco di dizionari in base al valore della chiave specifica, specificare il parametro chiave del metodo sort() o della funzione sorted().
Specificando una funzione da applicare a ciascun elemento dell’elenco, viene ordinata in base al risultato di tale funzione. Per ulteriori informazioni, vedere il seguente articolo.
In questo esempio, puoi specificare una funzione per ottenere il valore di una chiave specifica dal dizionario.
È possibile definire una funzione con def, ma in questo caso è conveniente utilizzare espressioni lambda.
pprint.pprint(sorted(l, key=lambda x: x['Age']))
# [{'Age': 20, 'Name': 'Bob'},
# {'Age': 30, 'Name': 'Charlie', 'Point': 70},
# {'Age': 40, 'Name': 'Alice', 'Point': 80}]
pprint.pprint(sorted(l, key=lambda x: x['Name']))
# [{'Age': 40, 'Name': 'Alice', 'Point': 80},
# {'Age': 20, 'Name': 'Bob'},
# {'Age': 30, 'Name': 'Charlie', 'Point': 70}]
Specificare se ordinare in ordine decrescente o crescente con il parametro reverse.
pprint.pprint(sorted(l, key=lambda x: x['Age'], reverse=True))
# [{'Age': 40, 'Name': 'Alice', 'Point': 80},
# {'Age': 30, 'Name': 'Charlie', 'Point': 70},
# {'Age': 20, 'Name': 'Bob'}]
Gli esempi finora utilizzati sorted(), ma puoi specificare key e reverse allo stesso modo con il metodo sort() di list.
Per la differenza tra sort() e sorted(), vedere il seguente articolo. sort() ordina l’oggetto originale stesso e sorted() crea un nuovo oggetto ordinato.
Quando la chiave specificata non esiste
Con il modo mostrato sopra, viene generato un errore se la chiave specificata non esiste.
# sorted(l, key=lambda x: x['Point'])
# KeyError: 'Point'
In tal caso, utilizzare il metodo get() dict, che restituisce il valore predefinito per chiavi inesistenti.
Per configurazione predefinita, get() restituisce Nessuno per chiavi inesistenti. Nessuno non è paragonabile a un numero oa una stringa, quindi viene generato un errore.
# sorted(l, key=lambda x: x.get('Point'))
# TypeError: '<' not supported between instances of 'int' and 'NoneType'
È possibile specificare un valore per una chiave che non esiste come secondo argomento di get(). Gli elementi le cui chiavi non vengono sostituiti con il valore specificato nel secondo argomento e ordinati.
pprint.pprint(sorted(l, key=lambda x: x.get('Point', 75)))
# [{'Age': 30, 'Name': 'Charlie', 'Point': 70},
# {'Age': 20, 'Name': 'Bob'},
# {'Age': 40, 'Name': 'Alice', 'Point': 80}]
Infinity inf è determinato come maggiore di qualsiasi altro numero, quindi puoi usare inf e -inf per posizionare sempre elementi senza chiave alla fine o all’inizio.
pprint.pprint(sorted(l, key=lambda x: x.get('Point', float('inf'))))
# [{'Age': 30, 'Name': 'Charlie', 'Point': 70},
# {'Age': 40, 'Name': 'Alice', 'Point': 80},
# {'Age': 20, 'Name': 'Bob'}]
pprint.pprint(sorted(l, key=lambda x: x.get('Point', -float('inf'))))
# [{'Age': 20, 'Name': 'Bob'},
# {'Age': 30, 'Name': 'Charlie', 'Point': 70},
# {'Age': 40, 'Name': 'Alice', 'Point': 80}]
Specificare operator.mgetter() per il parametro chiave
Puoi anche usare itemgetter() del modulo operatore della libreria standard. È più veloce dell’utilizzo di un’espressione lambda.
import operator
pprint.pprint(sorted(l, key=operator.itemgetter('Age')))
# [{'Age': 20, 'Name': 'Bob'},
# {'Age': 30, 'Name': 'Charlie', 'Point': 70},
# {'Age': 40, 'Name': 'Alice', 'Point': 80}]
pprint.pprint(sorted(l, key=operator.itemgetter('Name')))
# [{'Age': 40, 'Name': 'Alice', 'Point': 80},
# {'Age': 20, 'Name': 'Bob'},
# {'Age': 30, 'Name': 'Charlie', 'Point': 70}]
Se la chiave specificata non esiste, si verifica un errore.
# sorted(l, key=operator.itemgetter('Point'))
# KeyError: 'Point'
Ordina per più chiavi
Quello che segue è un esempio di un caso in cui i dizionari hanno lo stesso valore per una chiave comune. Due hanno dizionari il valore ‘CA’ per la chiave ‘Stato’.
l_dup = [{'Name': 'Alice', 'Age': 40, 'Point': 80, 'State': 'CA'},
{'Name': 'Bob', 'Age': 20, 'State': 'NY'},
{'Name': 'Charlie', 'Age': 30, 'Point': 70, 'State': 'CA'}]
Se i valori sono uguali, l’ordine originale viene mantenuto.
pprint.pprint(sorted(l_dup, key=operator.itemgetter('State')))
# [{'Age': 40, 'Name': 'Alice', 'Point': 80, 'State': 'CA'},
# {'Age': 30, 'Name': 'Charlie', 'Point': 70, 'State': 'CA'},
# {'Age': 20, 'Name': 'Bob', 'State': 'NY'}]
È possibile specificare più argomenti per operator.itemgetter() e, se i valori per la prima chiave sono uguali, verranno confrontati e ordinati in base al valore della chiave successiva.
pprint.pprint(sorted(l_dup, key=operator.itemgetter('State', 'Age')))
# [{'Age': 30, 'Name': 'Charlie', 'Point': 70, 'State': 'CA'},
# {'Age': 40, 'Name': 'Alice', 'Point': 80, 'State': 'CA'},
# {'Age': 20, 'Name': 'Bob', 'State': 'NY'}]
Si noti che se l’ordine degli argomenti è diverso, anche il risultato è diverso.
pprint.pprint(sorted(l_dup, key=operator.itemgetter('Age', 'State')))
# [{'Age': 20, 'Name': 'Bob', 'State': 'NY'},
# {'Age': 30, 'Name': 'Charlie', 'Point': 70, 'State': 'CA'},
# {'Age': 40, 'Name': 'Alice', 'Point': 80, 'State': 'CA'}]
Lo stesso può essere fatto con le espressioni lambda che restituiscono più valori come tuple o elenchi.
pprint.pprint(sorted(l_dup, key=lambda x: (x['State'], x['Age'])))
# [{'Age': 30, 'Name': 'Charlie', 'Point': 70, 'State': 'CA'},
# {'Age': 40, 'Name': 'Alice', 'Point': 80, 'State': 'CA'},
# {'Age': 20, 'Name': 'Bob', 'State': 'NY'}]
max(), min() per un elenco di dizionari
Come accennato in precedenza, i confronti con < o > non sono supportati per i dizionari dict, quindi passare un elenco di dizionari a max() o min() provoca un errore.
# max(l)
# TypeError: '>' not supported between instances of 'dict' and 'dict'
Come con sorted() e sort(), puoi anche specificare il parametro chiave in max() e min().
print(max(l, key=lambda x: x['Age']))
# {'Name': 'Alice', 'Age': 40, 'Point': 80}
print(min(l, key=lambda x: x['Age']))
# {'Name': 'Bob', 'Age': 20}
Viene restituito il dizionario dict, quindi se vuoi ottenere un valore, specifica una chiave.
print(max(l, key=lambda x: x['Age'])['Age'])
# 40
Ovviamente puoi anche usare operator.itemgetter().
print(max(l, key=operator.itemgetter('Age')))
# {'Name': 'Alice', 'Age': 40, 'Point': 80}