Recherche…


Obtenir le minimum ou le maximum de plusieurs valeurs

min(7,2,1,5)
# Output: 1

max(7,2,1,5)
# Output: 7

Utiliser l'argument clé

Trouver le minimum / maximum d'une séquence de séquences est possible:

list_of_tuples = [(0, 10), (1, 15), (2, 8)]
min(list_of_tuples)
# Output: (0, 10)

mais si vous voulez trier par un élément spécifique dans chaque séquence, utilisez l'argument key :

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

Argument par défaut à max, min

Vous ne pouvez pas passer une séquence vide dans max ou min :

min([])

ValueError: min () arg est une séquence vide

Cependant, avec Python 3, vous pouvez transmettre l'argument default avec une valeur qui sera renvoyée si la séquence est vide, au lieu de générer une exception:

max([], default=42)        
# Output: 42
max([], default=0)        
# Output: 0

Cas particulier: dictionnaires

Le minimum ou le maximum ou l'utilisation de sorted dépend des itérations sur l'objet. Dans le cas de dict , l'itération est uniquement sur les clés:

adict = {'a': 3, 'b': 5, 'c': 1}
min(adict)
# Output: 'a'
max(adict)
# Output: 'c'
sorted(adict)
# Output: ['a', 'b', 'c']

Pour conserver la structure du dictionnaire, vous devez parcourir le .items() :

min(adict.items())
# Output: ('a', 3)
max(adict.items())
# Output: ('c', 1)
sorted(adict.items())
# Output: [('a', 3), ('b', 5), ('c', 1)]

Pour sorted , vous pouvez créer un OrderedDict pour conserver le tri tout en ayant une structure de type dict :

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

Par valeur

Là encore, cela est possible en utilisant l'argument 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)]

Obtenir une séquence triée

En utilisant une séquence:

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

Le résultat est toujours une nouvelle list ; les données d'origine restent inchangées.

Minimum et Maximum d'une séquence

Obtenir le minimum d'une séquence (itérable) équivaut à accéder au premier élément d'une séquence sorted :

min([2, 7, 5])
# Output: 2
sorted([2, 7, 5])[0]
# Output: 2

Le maximum est un peu plus compliqué, car sorted garde l'ordre et max renvoie la première valeur rencontrée. S'il n'y a pas de doublons, le maximum est le même que le dernier élément du retour trié:

max([2, 7, 5])
# Output: 7
sorted([2, 7, 5])[-1]
# Output: 7

Mais pas si plusieurs éléments sont évalués comme ayant la valeur maximale:

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

Tout élément contenant des éléments pouvant supporter < ou > opérations est autorisé.

Rendre les classes personnalisées ordonnables

min , max et sorted doivent tous les objets être ordonnables. Pour être correctement classable, la classe doit définir toutes les 6 méthodes __lt__ , __gt__ , __ge__ , __le__ , __ne__ et __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

Bien que l'implémentation de toutes ces méthodes semble inutile, en omettre certaines rendra votre code sujet aux bogues .

Exemples:

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 avec reverse=True utilise également __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)]

Mais sorted peut utiliser __gt__ place si la valeur par défaut n’est pas implémentée:

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)

Les méthodes de tri TypeError une TypeError si ni __lt__ ni __gt__ sont implémentées:

del IntegerContainer.__gt__   # The IntegerContainer no longer implements "greater then"

res = min(alist) 

TypeError: types non ordonnables: IntegerContainer () <IntegerContainer ()


functools.total_ordering décorateur peut être utilisé pour simplifier l’écriture de ces riches méthodes de comparaison. Si vous décorez votre classe avec total_ordering , vous devez implémenter __eq__ , __ne__ et un seul des __lt__ , __le__ , __ge__ ou __gt__ , et le décorateur remplira le reste:

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

Notez que le > ( supérieur à ) finit maintenant par appeler la méthode less than et, dans certains cas, même la méthode __eq__ . Cela signifie également que si la vitesse est très importante, vous devez implémenter vous-même chaque méthode de comparaison enrichie.

Extraire N plus grand ou N plus petit élément d’une

Pour trouver un nombre (plus d'un) de la plus grande ou de la plus petite valeur d'une itération, vous pouvez utiliser le nlargest et le nsmallest du module heapq :

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]

Ceci est beaucoup plus efficace que de trier la totalité des itérables puis de les couper de la fin ou du début. En interne, ces fonctions utilisent la structure de données de la file d'attente du segment de mémoire binaire , ce qui est très efficace pour ce cas d'utilisation.

Comme min , max et sorted , ces fonctions acceptent l'option key argument de mot - clé, qui doit être une fonction qui, étant donné un élément, renvoie sa clé de tri.

Voici un programme qui extrait 1000 lignes les plus longues d'un fichier:

import heapq
with open(filename) as f:
    longest_lines = heapq.nlargest(1000, f, key=len)

Ici, nous ouvrons le fichier et transmettons le nlargest fichier f à la plus grande nlargest . Itérer le fichier donne à chaque ligne du fichier une chaîne distincte; nlargest passe ensuite chaque élément (ou ligne) est passé à la fonction len pour déterminer sa clé de tri. len , étant donné une chaîne, renvoie la longueur de la ligne en caractères.

Cela ne nécessite que le stockage pour une liste de 1000 lignes les plus grandes à ce jour, qui peut être comparée à

longest_lines = sorted(f, key=len)[1000:]

qui devra contenir tout le fichier en mémoire .



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow