Python Language
Ordinamento, minimo e massimo
Ricerca…
Ottenere il minimo o il massimo di più valori
min(7,2,1,5)
# Output: 1
max(7,2,1,5)
# Output: 7
Usando l'argomento chiave
È possibile trovare il minimo / massimo di una sequenza di sequenze:
list_of_tuples = [(0, 10), (1, 15), (2, 8)]
min(list_of_tuples)
# Output: (0, 10)
ma se vuoi ordinare da un elemento specifico in ogni sequenza usa il key
-argomento:
min(list_of_tuples, key=lambda x: x[0]) # Sorting by first element
# Output: (0, 10)
min(list_of_tuples, key=lambda x: x[1]) # Sorting by second element
# Output: (2, 8)
sorted(list_of_tuples, key=lambda x: x[0]) # Sorting by first element (increasing)
# Output: [(0, 10), (1, 15), (2, 8)]
sorted(list_of_tuples, key=lambda x: x[1]) # Sorting by first element
# Output: [(2, 8), (0, 10), (1, 15)]
import operator
# The operator module contains efficient alternatives to the lambda function
max(list_of_tuples, key=operator.itemgetter(0)) # Sorting by first element
# Output: (2, 8)
max(list_of_tuples, key=operator.itemgetter(1)) # Sorting by second element
# Output: (1, 15)
sorted(list_of_tuples, key=operator.itemgetter(0), reverse=True) # Reversed (decreasing)
# Output: [(2, 8), (1, 15), (0, 10)]
sorted(list_of_tuples, key=operator.itemgetter(1), reverse=True) # Reversed(decreasing)
# Output: [(1, 15), (0, 10), (2, 8)]
Argomento predefinito su max, min
Non è possibile passare una sequenza vuota in max
o min
:
min([])
ValueError: min () arg è una sequenza vuota
Tuttavia, con Python 3, puoi passare l'argomento della parola chiave default
con un valore che verrà restituito se la sequenza è vuota, invece di generare un'eccezione:
max([], default=42)
# Output: 42
max([], default=0)
# Output: 0
Caso speciale: dizionari
Ottenere il minimo o il massimo o utilizzare sorted
dipende dalle iterazioni sull'oggetto. Nel caso di dict
, l'iterazione è solo sopra i tasti:
adict = {'a': 3, 'b': 5, 'c': 1}
min(adict)
# Output: 'a'
max(adict)
# Output: 'c'
sorted(adict)
# Output: ['a', 'b', 'c']
Per mantenere la struttura del dizionario, è necessario eseguire iterazioni su .items()
:
min(adict.items())
# Output: ('a', 3)
max(adict.items())
# Output: ('c', 1)
sorted(adict.items())
# Output: [('a', 3), ('b', 5), ('c', 1)]
Per sorted
, è possibile creare un OrderedDict
per mantenere l'ordinamento pur avendo una dict
-come struttura:
from collections import OrderedDict
OrderedDict(sorted(adict.items()))
# Output: OrderedDict([('a', 3), ('b', 5), ('c', 1)])
res = OrderedDict(sorted(adict.items()))
res['a']
# Output: 3
In base al valore
Anche in questo caso è possibile utilizzare l'argomento key
:
min(adict.items(), key=lambda x: x[1])
# Output: ('c', 1)
max(adict.items(), key=operator.itemgetter(1))
# Output: ('b', 5)
sorted(adict.items(), key=operator.itemgetter(1), reverse=True)
# Output: [('b', 5), ('a', 3), ('c', 1)]
Ottenere una sequenza ordinata
Utilizzando una sequenza:
sorted((7, 2, 1, 5)) # tuple
# Output: [1, 2, 5, 7]
sorted(['c', 'A', 'b']) # list
# Output: ['A', 'b', 'c']
sorted({11, 8, 1}) # set
# Output: [1, 8, 11]
sorted({'11': 5, '3': 2, '10': 15}) # dict
# Output: ['10', '11', '3'] # only iterates over the keys
sorted('bdca') # string
# Output: ['a','b','c','d']
Il risultato è sempre una nuova list
; i dati originali rimangono invariati.
Minimo e Massimo di una sequenza
Ottenere il minimo di una sequenza (iterabile) equivale all'accesso al primo elemento di una sequenza sorted
:
min([2, 7, 5])
# Output: 2
sorted([2, 7, 5])[0]
# Output: 2
Il massimo è un po 'più complicato, perché sorted
mantiene l'ordine e max
restituisce il primo valore rilevato. Nel caso in cui non ci siano duplicati il massimo è uguale all'ultimo elemento del reso ordinato:
max([2, 7, 5])
# Output: 7
sorted([2, 7, 5])[-1]
# Output: 7
Ma non se ci sono più elementi che vengono valutati come aventi il valore massimo:
class MyClass(object):
def __init__(self, value, name):
self.value = value
self.name = name
def __lt__(self, other):
return self.value < other.value
def __repr__(self):
return str(self.name)
sorted([MyClass(4, 'first'), MyClass(1, 'second'), MyClass(4, 'third')])
# Output: [second, first, third]
max([MyClass(4, 'first'), MyClass(1, 'second'), MyClass(4, 'third')])
# Output: first
Sono permessi tutti gli elementi contenenti iterabili che supportano le operazioni <
o >
.
Rendi ordinabili le classi personalizzate
min
, max
e sorted
hanno bisogno che gli oggetti siano sorted
. Per essere correttamente ordinabile, la classe deve definire tutti i 6 metodi __lt__
, __gt__
, __ge__
, __le__
, __ne__
e __eq__
:
class IntegerContainer(object):
def __init__(self, value):
self.value = value
def __repr__(self):
return "{}({})".format(self.__class__.__name__, self.value)
def __lt__(self, other):
print('{!r} - Test less than {!r}'.format(self, other))
return self.value < other.value
def __le__(self, other):
print('{!r} - Test less than or equal to {!r}'.format(self, other))
return self.value <= other.value
def __gt__(self, other):
print('{!r} - Test greater than {!r}'.format(self, other))
return self.value > other.value
def __ge__(self, other):
print('{!r} - Test greater than or equal to {!r}'.format(self, other))
return self.value >= other.value
def __eq__(self, other):
print('{!r} - Test equal to {!r}'.format(self, other))
return self.value == other.value
def __ne__(self, other):
print('{!r} - Test not equal to {!r}'.format(self, other))
return self.value != other.value
Sebbene l'implementazione di tutti questi metodi non sia necessaria, l' omissione di alcuni di essi renderà il tuo codice soggetto a bug .
Esempi:
alist = [IntegerContainer(5), IntegerContainer(3),
IntegerContainer(10), IntegerContainer(7)
]
res = max(alist)
# Out: IntegerContainer(3) - Test greater than IntegerContainer(5)
# IntegerContainer(10) - Test greater than IntegerContainer(5)
# IntegerContainer(7) - Test greater than IntegerContainer(10)
print(res)
# Out: IntegerContainer(10)
res = min(alist)
# Out: IntegerContainer(3) - Test less than IntegerContainer(5)
# IntegerContainer(10) - Test less than IntegerContainer(3)
# IntegerContainer(7) - Test less than IntegerContainer(3)
print(res)
# Out: IntegerContainer(3)
res = sorted(alist)
# Out: IntegerContainer(3) - Test less than IntegerContainer(5)
# IntegerContainer(10) - Test less than IntegerContainer(3)
# IntegerContainer(10) - Test less than IntegerContainer(5)
# IntegerContainer(7) - Test less than IntegerContainer(5)
# IntegerContainer(7) - Test less than IntegerContainer(10)
print(res)
# Out: [IntegerContainer(3), IntegerContainer(5), IntegerContainer(7), IntegerContainer(10)]
sorted
con reverse=True
usa anche __lt__
:
res = sorted(alist, reverse=True)
# Out: IntegerContainer(10) - Test less than IntegerContainer(7)
# IntegerContainer(3) - Test less than IntegerContainer(10)
# IntegerContainer(3) - Test less than IntegerContainer(10)
# IntegerContainer(3) - Test less than IntegerContainer(7)
# IntegerContainer(5) - Test less than IntegerContainer(7)
# IntegerContainer(5) - Test less than IntegerContainer(3)
print(res)
# Out: [IntegerContainer(10), IntegerContainer(7), IntegerContainer(5), IntegerContainer(3)]
Ma sorted
può usare __gt__
se il default non è implementato:
del IntegerContainer.__lt__ # The IntegerContainer no longer implements "less than"
res = min(alist)
# Out: IntegerContainer(5) - Test greater than IntegerContainer(3)
# IntegerContainer(3) - Test greater than IntegerContainer(10)
# IntegerContainer(3) - Test greater than IntegerContainer(7)
print(res)
# Out: IntegerContainer(3)
I metodi di ordinamento __lt__
un TypeError
se non vengono implementati __lt__
né __gt__
:
del IntegerContainer.__gt__ # The IntegerContainer no longer implements "greater then"
res = min(alist)
TypeError: tipi non ordinabili: IntegerContainer () <IntegerContainer ()
functools.total_ordering
decorator può essere utilizzato semplificando lo sforzo di scrivere questi metodi di confronto ricchi. Se decori la tua classe con total_ordering
, devi implementare __eq__
, __ne__
e solo uno tra __lt__
, __le__
, __ge__
o __gt__
, e il decoratore riempirà il resto:
import functools
@functools.total_ordering
class IntegerContainer(object):
def __init__(self, value):
self.value = value
def __repr__(self):
return "{}({})".format(self.__class__.__name__, self.value)
def __lt__(self, other):
print('{!r} - Test less than {!r}'.format(self, other))
return self.value < other.value
def __eq__(self, other):
print('{!r} - Test equal to {!r}'.format(self, other))
return self.value == other.value
def __ne__(self, other):
print('{!r} - Test not equal to {!r}'.format(self, other))
return self.value != other.value
IntegerContainer(5) > IntegerContainer(6)
# Output: IntegerContainer(5) - Test less than IntegerContainer(6)
# Returns: False
IntegerContainer(6) > IntegerContainer(5)
# Output: IntegerContainer(6) - Test less than IntegerContainer(5)
# Output: IntegerContainer(6) - Test equal to IntegerContainer(5)
# Returns True
Si noti come >
( maggiore di ) ora finisce per chiamare il metodo meno di , e in alcuni casi anche il metodo __eq__
. Ciò significa anche che se la velocità è di grande importanza, è necessario implementare personalmente ciascun metodo di confronto ricco.
Estraendo N il più grande o il N più piccolo da un iterabile
Per trovare un numero (più di uno) dei valori più grandi o più piccoli di un iterabile, è possibile utilizzare il nlargest
e nsmallest
del heapq
modulo:
import heapq
# get 5 largest items from the range
heapq.nlargest(5, range(10))
# Output: [9, 8, 7, 6, 5]
heapq.nsmallest(5, range(10))
# Output: [0, 1, 2, 3, 4]
Questo è molto più efficiente dell'ordinamento dell'intero iterable e quindi dell'affinamento dalla fine o dall'inizio. Internamente queste funzioni utilizzano la struttura dati della coda di priorità heap binario , che è molto efficiente per questo caso d'uso.
Come min
, max
e sorted
, queste funzioni accettano l'argomento parola key
opzionale, che deve essere una funzione che, dato un elemento, restituisce la sua chiave di ordinamento.
Ecco un programma che estrae 1000 righe più lunghe da un file:
import heapq
with open(filename) as f:
longest_lines = heapq.nlargest(1000, f, key=len)
Qui apriamo il file e passiamo il file handle f
a nlargest
. L'iterazione del file produce ogni riga del file come una stringa separata; nlargest
passa quindi ogni elemento (o linea) viene passato alla funzione len
per determinare la sua chiave di ordinamento. len
, data una stringa, restituisce la lunghezza della linea in caratteri.
Questo ha solo bisogno di spazio per un elenco di 1000 linee più grandi finora, che può essere contrastato con
longest_lines = sorted(f, key=len)[1000:]
che dovrà conservare l'intero file in memoria .