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


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

примите во внимание массив ниже,

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

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

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

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

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

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

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

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

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

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

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 на dictionaries, вы можете изменить его в месте с sort() метод с использованием пользовательской ключевой функции.

основные функции:

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

    return d["name"]

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