Jak posortować listę słowników według wartości słownika?

Mam listę słowników i chcę, aby każdy element był sortowany według określonej wartości.

Weź pod uwagę listę:

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

Po posortowaniu według name powinno być:

[{'name':'Bart', 'age':10}, {'name':'Homer', 'age':39}]
Author: masi, 2008-09-16

17 answers

Może wyglądać czystiej używając klucza zamiast cmp:

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

Lub jak zasugerował J. F. Sebastian i inni,

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

Dla kompletności (jak zaznaczono w komentarzach fitzgeraldsteele), dodaj reverse=True do sortowania malejąco

newlist = sorted(l, key=itemgetter('name'), reverse=True)
 2707
Author: Mario F,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-31 19:39:49
import operator

Aby posortować listę słowników według klucza = 'nazwa':

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

Aby posortować listę słowników według klucza = 'wiek':

list_of_dicts.sort(key=operator.itemgetter('age'))
 183
Author: cedbeu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-01 14:42:05
my_list = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

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

my_list Teraz będziesz tym, czego chcesz.

Lub lepiej:

Od Pythona 2.4, istnieje key argument jest zarówno bardziej efektywny, jak i schludniejszy:

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

...lambda jest, IMO, łatwiejsze do zrozumienia niż operator.itemgetter, ale przebieg może się różnić.

 78
Author: pjz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-25 15:02:05

Jeśli chcesz posortować listę według wielu kluczy, możesz wykonać następujące czynności:

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

Jest to raczej hakerskie, ponieważ polega na konwersji wartości na pojedynczą reprezentację ciągów dla porównania, ale działa zgodnie z oczekiwaniami dla liczb, w tym ujemnych (chociaż będziesz musiał odpowiednio sformatować swój ciąg z zerowymi paddingami, jeśli używasz liczb).

 55
Author: Dologan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-14 20:43:57
import operator
a_list_of_dicts.sort(key=operator.itemgetter('name'))

'key' jest używany do sortowania według dowolnej wartości, a 'itemgetter' ustawia tę wartość do atrybutu 'name' każdego elementu.

 30
Author: efotinis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 14:43:51
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']) 
 30
Author: forzagreen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-17 10:29:50

Chyba miałeś na myśli:

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

To będzie posortowane TAK:

sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))
 22
Author: Bartosz Radaczyński,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 14:36:54

Możesz użyć niestandardowej funkcji porównawczej lub przekazać funkcję, która oblicza niestandardowy klucz sortowania. Jest to zwykle bardziej wydajne, ponieważ klucz jest obliczany tylko raz na przedmiot, podczas gdy funkcja porównania byłaby wywoływana wiele razy.

Możesz to zrobić w ten sposób:
def mykey(adict): return adict['name']
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=mykey)

Ale biblioteka Standardowa zawiera ogólną procedurę pobierania elementów dowolnych obiektów: itemgetter. Więc spróbuj tego zamiast:

from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name'))
 20
Author: Owen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 14:52:14

Używając transformaty Schwartziana z Perla,

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]

Daje

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

Więcej o transformacji Perla:

W informatyce transformata Schwartziana jest programowaniem Perla idiom używany do poprawy efektywności sortowania listy elementów. To idiom jest odpowiedni do sortowania opartego na porównaniach, gdy kolejność jest faktycznie na podstawie uporządkowania pewnej nieruchomości (klucza) z elementów, gdzie obliczanie tej własności jest intensywnej operacji, która należy wykonać minimalną liczbę razy. The Schwartzian Transform jest godny uwagi, ponieważ nie używa nazwanych tablic tymczasowych.

 20
Author: kiriloff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-14 20:48:11

Musisz zaimplementować własną funkcję porównywania, która porównuje słowniki według wartości kluczy nazw. Zobacz sortowanie Mini-Jak z PythonInfo Wiki

 18
Author: Matej,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 14:31:52

Czasami musimy użyć lower(). Na przykład,

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}]
 14
Author: uingtea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-22 13:49:19

Oto alternatywne ogólne rozwiązanie-sortuje elementy dict według kluczy i wartości.

Zaletą tego rozwiązania jest to, że nie trzeba podawać kluczy i nadal będzie działać, jeśli w niektórych słownikach brakuje niektórych kluczy.

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)
 11
Author: vvladymyrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-14 20:53:41

Używanie pakietu Pandas jest inną metodą, choć jej działanie na dużą skalę jest znacznie wolniejsze niż bardziej tradycyjne metody proponowane przez inne:

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

Oto kilka wartości wzorcowych dla małej listy i dużej (100k+) listy 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
 10
Author: abby sobh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-22 13:50:10

Załóżmy, że mam słownik D z poniższymi elementami. Aby posortować, po prostu użyj kluczowego argumentu w sorted, aby przekazać funkcję niestandardową jak poniżej:

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

Sprawdź to .

 7
Author: Shank_Transformer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-14 20:57:24

Jeśli nie potrzebujesz oryginalnego list z dictionaries, możesz zmodyfikować go na miejscu za pomocą metody sort() za pomocą niestandardowej funkcji klucza.

Funkcja klucza:

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

    return d["name"]

list do posortowania:

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

Sortowanie w miejscu:

data_one.sort(key=get_name)

Jeśli potrzebujesz oryginalnej list, wywołaj funkcję sorted() przekazując jej list i funkcję key, a następnie przypisz zwróconą sortowaną list do nowej zmiennej:

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

Drukowanie data_one i new_data.

>>> print(data_one)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
>>> print(new_data)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
 6
Author: srikavineehari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-19 17:31:30

Byłem wielkim fanem filtra z lambda. Jednak nie jest to najlepsza opcja, jeśli wziąć pod uwagę złożoność czasu.

Pierwsza opcja

sorted_list = sorted(list_to_sort, key= lambda x: x['name'])
# Returns list of values

Druga opcja

list_to_sort.sort(key=operator.itemgetter('name'))
# Edits the list, and does not return a new list

Szybkie porównanie czasów realizacji

# First option
python3.6 -m timeit -s "list_to_sort = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}, {'name':'Faaa', 'age':57}, {'name':'Errr', 'age':20}]" -s "sorted_l=[]" "sorted_l = sorted(list_to_sort, key=lambda e: e['name'])"

1000000 pętli, najlepiej 3: 0.736 µsec na pętlę

# Second option
python3.6 -m timeit -s "list_to_sort = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}, {'name':'Faaa', 'age':57}, {'name':'Errr', 'age':20}]" -s "sorted_l=[]" -s "import operator" "list_to_sort.sort(key=operator.itemgetter('name'))"

1000000 pętli, najlepiej 3: 0.438 µsec na pętlę

 5
Author: Bejür,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-14 21:00:19

Jeśli wydajność jest problemem, użyłbym operator.itemgetter zamiast lambda, ponieważ wbudowane funkcje działają szybciej niż ręcznie wykonane funkcje. itemgetter funkcja wydaje się działać około 20% szybciej niż lambda na podstawie moich testów.

Z https://wiki.python.org/moin/PythonSpeed:

Podobnie wbudowane funkcje działają szybciej niż ręcznie budowane odpowiedniki. Na przykład mapa (operator.add, v1, v2) jest szybszy niż map (lambda X,y: x+y, V1, v2).

Oto porównanie prędkości sortowania za pomocą lambda vs itemgetter.

import random
import operator

# Create a list of 100 dicts with random 8-letter names and random ages from 0 to 100.
l = [{'name': ''.join(random.choices(string.ascii_lowercase, k=8)), 'age': random.randint(0, 100)} for i in range(100)]

# Test the performance with a lambda function sorting on name
%timeit sorted(l, key=lambda x: x['name'])
13 µs ± 388 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# Test the performance with itemgetter sorting on name
%timeit sorted(l, key=operator.itemgetter('name'))
10.7 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# Check that each technique produces the same sort order
sorted(l, key=lambda x: x['name']) == sorted(l, key=operator.itemgetter('name'))
True

Obie techniki sortują listę w tej samej kolejności (weryfikowane przez wykonanie ostatecznej instrukcji w bloku kodu), ale pierwsza jest nieco szybsza.

 4
Author: swac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-14 21:01:56