Python Language
Sortering, minimum och max
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 .