Sök…


Få minsta eller högsta antal värden

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

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

Använd nyckelargumentet

Att hitta minimum / maximum för en sekvenssekvens är möjligt:

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

men om du vill sortera efter ett specifikt element i varje sekvens använder du 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)]

Standardargument till max, min

Du kan inte skicka en tom sekvens till max eller min :

min([])

ValueError: min () arg är en tom sekvens

Med Python 3 kan du emellertid överföra sökordsargumentets default med ett värde som kommer att returneras om sekvensen är tom istället för att höja ett undantag:

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

Specialfall: ordböcker

Att få minsta eller högsta eller använda sorted beror på iterationer över objektet. I fallet med dict är iterationen endast över nycklarna:

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

För att behålla ordboksstrukturen måste du iterera över .items() :

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

För sorted kan du skapa en OrderedDict att behålla sorteringen medan du har en dict liknande struktur:

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

Av värde

Återigen är detta möjligt med 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)]

Få en sorterad sekvens

Använd en sekvens:

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

Resultatet är alltid en ny list ; originaluppgifterna förblir oförändrade.

Minsta och högsta sekvens

Att få minsta möjliga sekvens (iterable) motsvarar tillgång till det första elementet i en sorted sekvens:

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

Maximumet är lite mer komplicerat, eftersom sorted behåller ordningen och max returnerar det första som uppstått. Om det inte finns några dubbletter är maximalen detsamma som det sista elementet i den sorterade returen:

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

Men inte om det finns flera element som utvärderas som har det maximala värdet:

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

Alla iterable som innehåller element som stöder < eller > operationer är tillåtna.

Gör anpassade klasser ordningsbara

min , max och sorted behöver alla objekt att vara ordningsbara. För att kunna ordnas ordentligt måste klassen definiera alla de 6 metoderna __lt__ , __gt__ , __ge__ , __le__ , __ne__ och __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

Även om att implementera alla dessa metoder verkar onödigt, kommer du att låta några av dem göra din kod benägen att bugga .

Exempel:

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 med reverse=True använder också __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)]

Men sorted kan använda __gt__ istället om standardinställningen inte är implementerad:

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)

Sorteringsmetoder höjer en TypeError om varken __lt__ eller __gt__ implementeras:

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

res = min(alist) 

TypeError: unorderable types: IntegerContainer () <IntegerContainer ()


functools.total_ordering dekoratör kan användas för att förenkla ansträngningen att skriva dessa rika jämförelsemetoder. Om du dekorerar din klass med total_ordering måste du implementera __eq__ , __ne__ och bara en av __lt__ , __le__ , __ge__ eller __gt__ , och dekoratören fyller i resten:

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

Lägg märke till hur > ( större än ) nu slutar ringa metoden mindre än , och i vissa fall till och med __eq__ metoden. Detta innebär också att om hastighet är av stor vikt, bör du implementera varje rik jämförelsemetod själv.

Extrahera N största eller N minsta föremål från en iterable

För att hitta ett antal (fler än ett) av de största eller minsta värdena på en iterable, kan du använda det nlargest och nsmallest av heapq modulen:

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]

Detta är mycket effektivare än att sortera hela den iterbara och sedan skära från slutet eller början. Internt använder dessa funktioner datakonstruktionen för binär högprioritetskö , vilket är mycket effektivt för detta användningsfall.

Liknande min , max och sorted , dessa funktioner accepterar det valfria key sökordet argument, som måste vara en funktion som, givet ett element, returnerar dess sorteringsnyckeln.

Här är ett program som extraherar 1000 längsta rader från en fil:

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

Här öppnar vi filen och nlargest filhandtaget f till största nlargest . Iterering av filen ger varje rad i filen som en separat sträng; nlargest passerar sedan varje element (eller linje) över till funktionen len att bestämma dess sorteringsknapp. len , med en sträng, returnerar längden på linjen i tecken.

Detta behöver endast lagring för en lista med 1000 största rader hittills, vilket kan kontrasteras med

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

som måste hålla hela filen i minnet .



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow