Как отсортировать словарь по убыванию?
Как его можно отсортировать по убыванию значения в ‘balance’? Мне необходимо получить:
users_database = < '639141904': , '609629735': >
Пару примеров, которыми я пытался получить необходимый результат:
users_database =
users_database = sorted(users_database, key=lambda x: int(x['balance']))
Прошу оставить читаемый и понятный код, который можно будет самостоятельно разобрать и понять что к чему, иные идеи / предложения / коды прошу оставлять в качестве комментария на этот вопрос.
Отслеживать
51.6k 201 201 золотой знак 63 63 серебряных знака 245 245 бронзовых знаков
задан 8 мар 2021 в 9:35
869 3 3 золотых знака 8 8 серебряных знаков 30 30 бронзовых знаков
Хотя сама задаче не очень правильно поставлена. Словарь не во всех версиях питона гарантирует порядок ключей. Лучше сортировать список ключей нужным образом, а потом по этим сортированным ключам уже выбирать из словаря данные. Как именно сортирует и хранит данные внутри себя словарь, в каком конкретном порядке — это должно быть неважно.
Сортировка по убыванию и возрастанию
Получение минимума или максимума нескольких значений
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 :
ValueError: min () arg — пустая последовательность
Однако, с Python 3, вы можете передать в аргументе ключевого слова по default со значением , которое будет возвращено , если последовательность пуста, а не поднимать исключение:
max([], default=42) # Output: 42 max([], default=0) # Output: 0
Особый случай: словари
Получение минимального или максимального или с использованием sorted зависит от итераций над объектом. В случае dict , итерация только по клавишам:
adict = 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() # set # Output: [1, 8, 11] sorted() # 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(' - Test less than '.format(self, other)) return self.value < other.value def __le__(self, other): print('- Test less than or equal to '.format(self, other)) return self.value <= other.value def __gt__(self, other): print('- Test greater than '.format(self, other)) return self.value > other.value def __ge__(self, other): print(' - Test greater than or equal to '.format(self, other)) return self.value >= other.value def __eq__(self, other): print(' - Test equal to '.format(self, other)) return self.value == other.value def __ne__(self, other): print(' - Test not equal to '.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 ()
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(' - Test less than '.format(self, other)) return self.value < other.value def __eq__(self, other): print('- Test equal to '.format(self, other)) return self.value == other.value def __ne__(self, other): print(' - Test not equal to '.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:]
которые должны будут держать весь файл в памяти.
Сортировка словаря по значению и/или ключу в Python
Сортировка словарей производится при помощи встроенной функцией sorted() и происходит немного сложнее чем сортировка списков или кортежей.
Сортировка словаря по ключу.
Функция sorted() работает со всеми объектами, которые поддерживают итерирование. Словарь, в свою очередь при итерировании, выдает только ключи, но нам необходимо получить исходный отсортированный словарь, а не только отсортированные ключи. Следовательно из словаря необходимо получить итерацию [(key, val), (key, val), . ] , затем отсортировать ее по значению key и преобразовать обратно в словарь.
Список кортежей (key, val) можно получить методом словаря dict.items() .
>>> d = 'b': 9, 'a': 3, 'c': 7> # получаем итерацию кортежей `(key, val)` >>> d.items() # dict_items([('b', 9), ('a', 3), ('c', 7)]) # то что нужно
Так как значение key стоит первым, то и ключ для сортировки укажем как lambda x: x[0] , где x - это кортеж (key, val)
# исходный словарь >>> d = 'b': 9, 'a': 3, 'c': 7> # собственно сама сортировка >>> sorted_tuple = sorted(d.items(), key=lambda x: x[0]) # получили отсортированный список кортежей, # отсортированных по первому значению >>> sorted_tuple # [('a', 3), ('b', 9), ('c', 7)] # преобразовываем обратно в словарь dict(sorted_tuple) #
Сортировка словаря по значению.
Применяя методику сортировки описанную выше, можно легко догадаться как сортировать словарь по значению. Для этого просто укажем в качестве ключа сортировки индекс значения словаря в полученном списке кортежей: lambda x: x[1] , где x - это кортеж (key, val)
>>> d = 'b': 9, 'a': 3, 'c': 7> >>> sorted_tuple = sorted(d.items(), key=lambda x: x[1]) >>> sorted_tuple # [('a', 3), ('c', 7), ('b', 9)] # преобразовываем обратно в словарь >>> dict(sorted_tuple) #
Для получения ключа сортировки из dict.items() , так же можно использовать функцию operator.itemgetter() :
>>> d = 'b': 9, 'a': 3, 'c': 7> >>> import operator >>> sorted_tuple = sorted(d.items(), key=operator.itemgetter(1)) >>> sorted_tuple # [('a', 3), ('c', 7), ('b', 9)] >>> dict(sorted_tuple) #
- ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
- Представления словарей dict.keys, dict.values и dict.items
- Исходный словарь для представления dictview.mapping
- Получение списка ключей словаря list(dict)
- Количество элементов в словаре len(dict)
- Доступ к значению словаря по ключу dict[key]
- Добавление/изменение значения словаря по ключу key
- Удаление значения словаря по ключу
- Проверка наличия/отсутствия ключа key в словаре dict
- Проверка наличия/отсутствия значения value в словаре Python
- Проверка наличия/отсутствия пары (key, value) в словаре dict
- Итерирование по ключам и значениям словаря Python
- Метод dict.clear(). Очистить словарь
- Метод dict.copy(), копия словаря
- Метод dict.fromkeys(), словарь с ключами по умолчанию
- Метод dict.get(), значение по умолчанию если ключа нет
- Метод dict.items(), список кортежей
- Метод dict.keys(), список ключей словаря
- Метод dict.values(), список значений словаря
- Метод dict.pop()
- Метод dict.popitem(), получить пару ключ/значение
- Метод dict.setdefault(), получает/вставляет значение ключа
- Метод dict.update(), обновление/дополнение словаря
- Объединение двух словарей в новый словарь Python
- Сортировка словаря по значению и/или ключу
- Обратный порядок/реверс словаря reversed(dict)
- Генератор словаря и его использование
- Фильтр словаря по ключам и/или значениям
- Словарь как фабрика функций
Сортировки и лямбда-функции
У стандартной сортировки (метода sort списка, функции sorted) есть более универсальный способ задания порядка сортировки при помощи параметра key. Значение этого параметра некоторая функция, которая вызывается для каждого элемента, перед сравнением этих элементов: элементы списка сортируются, но сравниваются не значения элементов, а результат вызова переданной функции от этого элемента.
Например, пусть дан список строк, содержащих цифры, нужно упорядочить элементы списка, сравнивая их, как числа, а не как строки. Это можно сделать так:
a = ["10", "20", "30", "1", "2", "3", "111", "112", "222"] a.sort(key=int)
В сложных случаях функцию нужно написать самостоятельно, например, пусть дан список чисел, который нужно упорядочить по последней цифре. Напишем функцию, которая возвращает последнюю цифру числа:
def last_digit(n): return n % 10 a.sort(key=last_digit)
Параметр key можно использовать вместе с параметром reverse .
Лямбда-функции
В предыдущем примере пришлось создавать отдельную функцию только для того, чтобы задать порядок сортировки, что захламляет программу ненужными функциями. В таких случаях нужно использовать лямбда-функции: “одноразовые фукцнии, которые можно объявлять без использовать слова def , прямо при вызове сортировки. Лямбда-функция — это функция, которая состоит только из одной строки с инструкцией return , то есть функция сразу возвращает значение по набору аргументов. Лямбда-функции объявляются таким образом:
lambda список переменных-аргументов: возвращаемое значение
Например, отсортировать список чисел по последней цифре можно при помощи следующей лямбда-функции:
a = [3, 15, 22, 13, 12, 32, 45, 43] a.sort(key=lambda n: n % 10)
Рассмотрим другой пример. Пусть дан список точек, каждая точка: кортеж из двух чисел. Например, [(3, -2), (7, 1), (0, 4)] . Этот список нужно отсортировать по возрастанию расстояния от начала координат до точки. Напишем лямбда-функцию:
a.sort(key=lamda point: point[0] ** 2 + point[1] ** 2)
Элементами списка являются кортежи из двух координат, можно обратиться к этим координатам по индексам [0] и [1].
Устойчивость сортировки
Вернёмся к примеру сортировки по последней цифре. В приведённом выше примере упорядоченный список будет таким:
[22, 12, 32, 3, 13, 43, 15, 45]
Этот пример иллюстрирует свойство устойчивости сортировки: функция сортировки не переставлят элементы, если они равны друг другу. В данном случае функция упорядочивает числа по последней цифре, а при равной последней цифре сохраняется порядок следования элементов в исходном списке: 22, 12, 32.
Что делать, если нужно сделать сложную сортировку, учитывающую несколько критериев? Например, при равной последней цифре нужно упорядочить элементы в порядке возрастания самих чисел.
Первый способ решения: напишем функцию, которая будет возвращать кортеж из двух чисел: последней цифры и самого числа. Кортежи сравниваются в лексикографическом порядке, поэтому при равенстве остатка от деления будут сравниваться сами числа.
a.sort(key=lambda n: (n % 10, n))
Второй способ: воспользуемся устойчивостью сортировки. Отстортируем список сначала по возрастанию чисел, а затем — по последней цифре. Тогда при равном значении последней цифры сохранится ранее полученный порядок.
a.sort() a.sort(key=lambda n: n % 10)
То есть сортировку по \(k\) параметрам (если по первому параметру элементы равны, то сравнить по второму, если равны два параметра, то сравнить по третьему и т.д.) можно заменить на \(k\) последовательных сортировок, выполняющихся в обратном порядке (от наименее значимого параметра к наиболее значимому).
Функция operator.itemgetter
При сортировке кортежей частой задачей является сортировка по какому-то одному элементу кортежа. Например, если нужно отсортировать кортежи по элементу с индексом 1, то можно написать такую лямбда-функцию:
a.sort(key=lambda elem: elem[1])
Для удобства в модуле operator есть функция itemgetter , которая позволяет создавать подобные функции, а именно, функция реализована примерно так:
def itemgetter(i): return lambda elem: elem[i]
То есть operator.itemgetter(i) — это функция, при вызове которой от числового параметра создаётся лямдба-функция, которую можно использовать в качестве параметра key . Если вызвать функцию itemgetter от нескольких параметров, то полученная функция будет возвращать кортеж из элементов с заданными индексами.