Как мне отсортировать список словарей по значению словаря?

StackOverflow https://stackoverflow.com/questions/72899

Вопрос

У меня есть список словарей, и я хочу, чтобы каждый элемент был отсортирован по определенному значению свойства.

Примите во внимание приведенный ниже массив,

[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

При сортировке по name, должен стать

[{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]
Это было полезно?

Решение

Это может выглядеть чище при использовании ключа вместо cmp:

newlist = sorted(list_to_be_sorted, key=lambda k: k['name']) 

или, как предположили Дж.Ф. Себастьян и другие,

from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name')) 

Для полноты картины (как указано в комментариях Фицджеральдстила), добавьте reverse=True для сортировки по убыванию

newlist = sorted(l, key=itemgetter('name'), reverse=True)

Другие советы

import operator

Отсортировать список словарей по ключу='name':

list_of_dicts.sort(key=operator.itemgetter('name'))

Отсортировать список словарей по ключу='возраст':

list_of_dicts.sort(key=operator.itemgetter('age'))

Если вы хотите отсортировать список по нескольким ключам, вы можете сделать следующее:

my_list = [{'name':'Homer', 'age':39}, {'name':'Milhouse', 'age':10}, {'name':'Bart', 'age':10} ]
sortedlist = sorted(my_list , key=lambda elem: "%02d %s" % (elem['age'], elem['name']))

Это довольно хакерский метод, поскольку он основан на преобразовании значений в одностроковое представление для сравнения, но он работает, как и ожидалось, для чисел, включая отрицательные (хотя вам нужно будет соответствующим образом отформатировать вашу строку с нулевыми дополнениями, если вы используете числа)

my_list = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

my_list.sort(lambda x,y : cmp(x['name'], y['name']))

my_list теперь будет то, что вы хотите.

(3 года спустя) Отредактировано для добавления:

Новый key аргументация более эффективна и аккуратна.Лучший ответ теперь выглядит следующим образом:

my_list = sorted(my_list, key=lambda k: k['name'])

... лямбда, ИМО, легче понять, чем operator.itemgetter, но YMMV.

import operator
a_list_of_dicts.sort(key=operator.itemgetter('name'))

'key' используется для сортировки по произвольному значению, а 'itemgetter' присваивает это значение атрибуту 'name' каждого элемента.

a = [{'name':'Homer', 'age':39}, ...]

# This changes the list a
a.sort(key=lambda k : k['name'])

# This returns a new list (a is not modified)
sorted(a, key=lambda k : k['name']) 

Я предполагаю, что ты имел в виду:

[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

Это было бы отсортировано следующим образом:

sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))

Использование преобразования Шварца из Perl,

py = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

делай

sort_on = "name"
decorated = [(dict_[sort_on], dict_) for dict_ in py]
decorated.sort()
result = [dict_ for (key, dict_) in decorated]

дает

>>> result
[{'age': 10, 'name': 'Bart'}, {'age': 39, 'name': 'Homer'}]

Подробнее о Преобразование Perl Шварца

В информатике преобразование Шварца - это идиома программирования на Perl , используемая для повышения эффективности сортировки списка элементов.Эта идиома подходит для сортировки на основе сравнения, когда упорядочение фактически основано на упорядочении определенного свойства (ключа) элементов, где вычисление этого свойства является трудоемкой операцией, которая должно выполняться минимальное количество раз.Преобразование Шварца примечательно тем, что в нем не используются именованные временные массивы.

Вы могли бы использовать пользовательскую функцию сравнения или передать функцию, которая вычисляет пользовательский ключ сортировки.Обычно это более эффективно, поскольку ключ вычисляется только один раз для каждого элемента, в то время как функция сравнения будет вызываться еще много раз.

Вы могли бы сделать это таким образом:

def mykey(adict): return adict['name']
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=mykey)

Но стандартная библиотека содержит общую процедуру для получения элементов произвольных объектов: itemgetter.Так что попробуйте вместо этого вот это:

from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name'))

Вы должны реализовать свою собственную функцию сравнения, которая будет сравнивать словари по значениям именных ключей.Видишь Мини-РУКОВОДСТВО по сортировке из PythonInfo Wiki

Вот альтернативное общее решение - оно сортирует элементы dict по ключам и значениям.Преимущество этого - нет необходимости указывать ключи, и это все равно будет работать, если некоторые ключи отсутствуют в некоторых словарях.

def sort_key_func(item):
    """ helper function used to sort list of dicts

    :param item: dict
    :return: sorted list of tuples (k, v)
    """
    pairs = []
    for k, v in item.items():
        pairs.append((k, v))
    return sorted(pairs)
sorted(A, key=sort_key_func)

когда-нибудь нам нужно будет использовать lower() например

lists = [{'name':'Homer', 'age':39},
  {'name':'Bart', 'age':10},
  {'name':'abby', 'age':9}]

lists = sorted(lists, key=lambda k: k['name'])
print(lists)
# [{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}, {'name':'abby', 'age':9}]

lists = sorted(lists, key=lambda k: k['name'].lower())
print(lists)
# [ {'name':'abby', 'age':9}, {'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]

Я пробовал что-то вроде этого:

my_list.sort(key=lambda x: x['name'])

Это работало и для целых чисел.

Использование пакета pandas - это еще один метод, хотя его время выполнения в больших масштабах намного медленнее, чем у более традиционных методов, предложенных другими:

import pandas as pd

listOfDicts = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
df = pd.DataFrame(listOfDicts)
df = df.sort_values('name')
sorted_listOfDicts = df.T.to_dict().values()

Вот некоторые контрольные значения для крошечного списка и большого (более 100 тысяч) списка dicts:

setup_large = "listOfDicts = [];\
[listOfDicts.extend(({'name':'Homer', 'age':39}, {'name':'Bart', 'age':10})) for _ in range(50000)];\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(listOfDicts);"

setup_small = "listOfDicts = [];\
listOfDicts.extend(({'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}));\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(listOfDicts);"

method1 = "newlist = sorted(listOfDicts, key=lambda k: k['name'])"
method2 = "newlist = sorted(listOfDicts, key=itemgetter('name')) "
method3 = "df = df.sort_values('name');\
sorted_listOfDicts = df.T.to_dict().values()"

import timeit
t = timeit.Timer(method1, setup_small)
print('Small Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_small)
print('Small Method LC2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup_small)
print('Small Method Pandas: ' + str(t.timeit(100)))

t = timeit.Timer(method1, setup_large)
print('Large Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_large)
print('Large Method LC2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup_large)
print('Large Method Pandas: ' + str(t.timeit(1)))

#Small Method LC: 0.000163078308105
#Small Method LC2: 0.000134944915771
#Small Method Pandas: 0.0712950229645
#Large Method LC: 0.0321750640869
#Large Method LC2: 0.0206089019775
#Large Method Pandas: 5.81405615807

Допустим, у меня есть словарь D с элементами ниже.Для сортировки просто используйте ключевой аргумент в sorted для передачи пользовательской функции, как показано ниже

D = {'eggs': 3, 'ham': 1, 'spam': 2}

def get_count(tuple):
    return tuple[1]

sorted(D.items(), key = get_count, reverse=True)
or
sorted(D.items(), key = lambda x: x[1], reverse=True)  avoiding get_count function call

https://wiki .python.org/moin/HowTo/Sorting/#Key_Functions

Вот мой ответ на связанный с этим вопрос о сортировке по нескольким столбцам.Это также работает для вырожденного случая, когда количество столбцов равно только одному.

Если вам не нужен оригинал list из dictionaries, вы могли бы изменить его на месте с помощью sort() метод с использованием пользовательской ключевой функции.

Ключевая функция:

def get_name(d):
    """ Return the value of a key in a dictionary. """

    return d["name"]

Тот Самый list подлежащий сортировке:

data_one = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]

Сортировка его на месте:

data_one.sort(key=get_name)

Если вам нужен оригинал list, вызовите sorted() функция, передающая ему list и ключевая функция, затем назначьте возвращаемое отсортированное list к новой переменной:

data_two = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]
new_data = sorted(data_two, key=get_name)

Печать data_one и new_data.

>>> print(data_one)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
>>> print(new_data)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]

Вы можете использовать элемент получения , если вы хотите рассмотреть производительность. элемент получения обычно работает немного быстрее, чем лямбда.

from operator import itemgetter
result = sorted(data, key=itemgetter('age'))  # this will sort list by property order 'age'.

Вы можете использовать следующий код

sorted_dct = sorted(dct_name.items(), key = lambda x : x[1])
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top