Получение минимума или максимума нескольких значений
min(7,2,1,5)
# Output: 1
max(7,2,1,5)
# Output: 7
Использование ключевого аргумента
Нахождение минимума / максимума последовательности последовательностей возможно:
list_of_tuples = [(0, 10), (1, 15), (2, 8)]
min(list_of_tuples)
# Output: (0, 10)
но если вы хотите отсортировать по определенному элементу в каждой последовательности с помощью key
-argument:
min(list_of_tuples, key=lambda x: x[0]) # Сортировка по первому элементу
# Output: (0, 10)
min(list_of_tuples, key=lambda x: x[1]) # Сортировка по второму элементу
# Output: (2, 8)
sorted(list_of_tuples, key=lambda x: x[0]) # Сортировка по первому элементу по возрастанию
# Output: [(0, 10), (1, 15), (2, 8)]
sorted(list_of_tuples, key=lambda x: x[1]) # Сортивровка по второму элементу по возрастанию
# Output: [(2, 8), (0, 10), (1, 15)]
import operator
# Оператор module содержит коэффициенты альтернативные лямбда функции
max(list_of_tuples, key=operator.itemgetter(0)) # Сортировка по первому элементу
# Output: (2, 8)
max(list_of_tuples, key=operator.itemgetter(1)) # Сортировка по второму элементу
# 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)]
Аргумент по умолчанию для max, min
Вы не можете передать пустую последовательность в max
или min
:
min([])
ValueError: min () arg - пустая последовательность
Однако, с Python 3, вы можете передать в аргументе ключевого слова по default
со значением , которое будет возвращено , если последовательность пуста, а не поднимать исключение:
max([], default=42)
# Output: 42
max([], default=0)
# Output: 0
Особый случай: словари
Получение минимального или максимального или с использованием sorted
зависит от итераций над объектом. В случае dict
, итерация только по клавишам:
adict = {'a': 3, 'b': 5, 'c': 1}
min(adict)
# Output: 'a'
max(adict)
# Output: 'c'
sorted(adict)
# Output: ['a', 'b', 'c']
Чтобы сохранить словарную структуру, вы должны перебрать .items()
:
min(adict.items())
# Output:('a', 3)
max(adict.items())
# Output:('c', 1)
sorted(adict.items())
# Output: [('a', 3),('b', 5),('c', 1)]
Для sorted
, можно создать OrderedDict
сохранить сортировку, имея dict
-like структуру:
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
По значению
Опять же, это возможно с помощью 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)]
Получение отсортированной последовательности
Используя одну последовательность:
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']
Результат всегда новый list
; исходные данные остаются без изменений.
Минимум и максимум последовательности
Получение минимума последовательности (Iterable) является эквивалентом доступа к первому элементу в sorted
последовательностях:
min([2, 7, 5])
# Output: 2
sorted([2, 7, 5])[0]
# Output: 2
Максимум является немного более сложной, потому что sorted
сохраняет порядок и max
возвращает первое значение встречается. В случае отсутствия дубликатов максимум совпадает с последним элементом отсортированного возврата:
max([2, 7, 5])
# Output: 7
sorted([2, 7, 5])[-1]
# Output: 7
Но нет, если есть несколько элементов, которые оцениваются как имеющие максимальное значение:
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
Любая итерация , содержащие элементы , которые поддерживают <
или >
операции разрешены.
Сделать пользовательские классы заказанными
min
, max
, и sorted
все должны объекты быть упорядочиваема. Для того, чтобы быть правильно упорядочиваема, класс должен определить все 6 методов __lt__
, __gt__
, __ge__
, __le__
, __ne__
и __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
Хотя осуществление всех этих методов может показаться ненужным, опуская некоторые из них сделает ваш код склонной к ошибкам .
Примеры:
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
с reverse=True
, также использует __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)]
Но sorted
можно использовать __gt__
вместо этого , если по умолчанию не выполняется:
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)
Сортировка методов поднимет TypeError
, если ни __lt__
, ни __gt__
реализованы:
del IntegerContainer.__gt__ # The IntegerContainer no longer implements "greater then"
res = min(alist)
Ошибка типа: неупорядоченные типы: IntegerContainer () <IntegerContainer ()
functools.total_ordering
декоратор может использоваться упрощая возможность написания этих богатых методы сравнения. Если вы украшаете свой класс с total_ordering
, вам нужно реализовать __eq__
, __ne__
и только один из __lt__
, __le__
, __ge__
или __gt__
и декоратор заполнит в остальном:
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
Обратите внимание на то, как >
(больше) Теперь заканчивается вызовом меньше , чем метод, а в некоторых случаях даже __eq__
метод. Это также означает, что, если скорость имеет большое значение, вы должны самостоятельно реализовать каждый метод сравнения.
Извлечение N самых больших или N самых маленьких элементов из итерируемого
Для того, чтобы найти некоторое количество (более одного) из больших или мельчайших значений итератора, вы можете использовать nlargest
и nsmallest
из 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]
Это гораздо эффективнее, чем сортировка всего итерируемого и затем нарезка с конца или начала. Внутри эти функции используют бинарные кучи приоритетной очереди структуру данных, которая является очень эффективной для этого случая использования.
Как min
, max
и sorted
, эти функции принимают дополнительный key
ключевого слова аргумента, который должен быть функцией , которая, учитывая элемент, возвращает ключ сортировки.
Вот программа, которая извлекает 1000 самых длинных строк из файла:
import heapq
with open(filename) as f:
longest_lines = heapq.nlargest(1000, f, key=len)
Здесь мы открываем файл и передать дескриптор файла f
в nlargest
.Повторение файла дает каждую строку файла как отдельную строку; nlargest
затем проходит каждый элемент (или линия) передается функции len
, чтобы определить его ключ сортировки. len
, учитывая строку, возвращает длину строки в символах.
Это требует только хранилища для списка из 1000 самых больших строк, которые можно сравнить с
longest_lines = sorted(f, key=len)[1000:]
которые должны будут держать весь файл в памяти.