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____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 .



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow