it-swarm-ru.tech

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

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

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

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

Когда отсортировано по name, должно стать

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

Это может выглядеть чище, используя ключ вместо 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)
2038
Mario F
import operator

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

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

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

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

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

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

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

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

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

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

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

26
efotinis

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

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

Это будет отсортировано так:

sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))
18
Bartosz Radaczyński

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

17
octoback
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']) 
15
forzagreen

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

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

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

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

14
Matej

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

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

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

10
Sandip Agarwal

иногда нам нужно использовать 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}]
9
uingtea

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

Использование пакета 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 тыс.) Списка диктов:

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
8
abby sobh

Скажем, у меня есть словарь 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

5
Shank_Transformer

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

4
hughdbrown

Если вам не нужен исходный 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}]
2
Srisaila

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

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

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

sorted_dct = sorted(dct_name.items(), key = lambda x : x[1])
0
Loochie