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

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

учитывать массиве ниже

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

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

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

17 ответов


он может выглядеть чище, используя ключ вместо 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')) 

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

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

import operator

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

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

чтобы отсортировать список словарей по ключу= 'age':

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 ' каждого элемента.


Я думаю, вы имели в виду:

[{'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}]

do

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 идиома используется для повышения эффективности сортировки списка элементов. Этот идиома подходит для сортировки на основе сравнения, когда порядок фактически основанный на заказе определенного свойства (the ключ) элементы, где вычисление этого свойства является интенсивной операцией, которая должно выполняться минимальное количество раз. На Шварца Transform примечателен тем, что он не использует именованные временные массивы.


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

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

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


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

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

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

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


вот альтернативное общее решение-он сортирует элементы 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)

использование пакета 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()

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

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

иногда нам нужно использовать

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

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

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 of 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}]