it-swarm-eu.dev

Jak lze třídit seznam slovníků hodnotou slovníku?

Mám seznam slovníků a chci, aby každá položka byla řazena podle konkrétních hodnot vlastností.

Vezměte v úvahu pole níže,

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

Při třídění podle name by se mělo stát

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

Místo toho může vypadat čistěji pomocí klíče a cmp:

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

nebo jak navrhl J.F.Sebastian a další,

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

Pro úplnost (jak je uvedeno v komentářích fitzgeraldsteele) přidejte reverse=True pro řazení sestupně

newlist = sorted(l, key=itemgetter('name'), reverse=True)
2038
Mario F
import operator

Seřazení seznamu slovníků podle klíče = 'name':

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

Seřazení seznamu slovníků podle klíče = 'věk':

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

Pokud chcete seznam seřadit podle více klíčů, můžete provést následující:

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

To je poněkud hackish, protože to se spoléhá na konverzi hodnot do reprezentace jednoho řetězce pro srovnání, ale to funguje jak očekával pro čísla včetně těch záporných (ačkoli vy budete muset formátovat váš řetězec vhodně s nulovými výplněmi jestliže vy používáte čísla)

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 bude nyní to, co chcete.

(3 roky později) Upraveno pro přidání:

Nový argument key je efektivnější a neater. Lepší odpověď nyní vypadá takto:

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

lambda je, IMO, lépe pochopitelná než operator.itemgetter, ale YMMV.

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

'key' se používá k třídění podle libovolné hodnoty a 'itemgetter' nastavuje tuto hodnotu na atribut 'name' každé položky.

26
efotinis

Myslím, že jste myslel:

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

Toto by bylo řazeno takto:

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

Použití Schwartzianovy transformace z Perlu,

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

dělat

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

dává

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

Více o Transformace Perl Schwartzian

V počítačové vědě je Schwartzianova transformace perlovým programováním , Které se používá ke zlepšení účinnosti třídění seznamu položek. Tento idiom je vhodný pro srovnávání založené na srovnávání, když je objednávka Skutečně založena na uspořádání určité vlastnosti (klíče) prvků , Kde výpočet této vlastnosti je intenzivní operaci, která by měla být prováděna minimálně . Schwartzian Transformace je pozoruhodná v tom, že nepoužívá pojmenovaná dočasná pole.

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

Můžete použít vlastní funkci porovnávání nebo můžete předat funkci, která vypočítává vlastní klíč řazení. To je obvykle efektivnější, protože klíč je počítán pouze jednou za položku, zatímco srovnávací funkce by byla nazývána mnohem vícekrát.

Můžete to udělat takto:

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

Standardní knihovna však obsahuje obecnou rutinu pro získávání položek libovolných objektů: itemgetter. Zkuste to místo toho:

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

Musíte implementovat vlastní porovnávací funkci, která bude porovnávat slovníky hodnotami jmenných klíčů. Viz Třídění Mini-HOW TO z PythonInfo Wiki

14
Matej

Zkusil jsem něco takového:

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

Fungovalo to i pro celá čísla.

10
Sandip Agarwal

někdy musíme použít například 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

Zde je alternativní obecné řešení - třídí prvky diktů pomocí klíčů a hodnot. Výhodou je, že není třeba specifikovat klíče, a přesto by v některých slovnících fungovalo, kdyby některé klíče chyběly.

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

Používání balíčku pandas je další metodou, i když je runtime ve velkém měřítku mnohem pomalejší než tradiční metody navržené jinými uživateli:

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

Zde jsou některé hodnoty benchmarků pro malý seznam a velký (100k +) seznam diktů:

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

Řekněme, že h'v slovník D s prvky níže. Chcete-li třídit, použijte klíčový argument ve třídě a předejte vlastní funkci, jak je uvedeno níže

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

Zde je moje odpověď na související otázku o třídění podle více sloupců . Funguje také pro degenerovaný případ, kdy počet sloupců je pouze jeden.

4
hughdbrown

Pokud nepotřebujete původní listdictionaries, můžete ji upravit pomocí metody sort() pomocí funkce vlastního klíče.

Funkce klíče:

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

    return d["name"]

list má být řazeno:

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

Řazení na místě:

data_one.sort(key=get_name)

Pokud potřebujete původní list, zavolejte funkci sorted() a předejte ji list a funkci klíče, pak přiřaďte vrácenou třídu list nové proměnné:

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

Tisk data_one a 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

Můžete použít itemgetter , pokud chcete zvážit výkon. itemgetter typicky běží rychleji než lambda .

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

Můžete použít následující kód

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