Відповіді:
Це може виглядати чистіше, використовуючи ключ замість cmp:
newlist = sorted(list_to_be_sorted, key=lambda k: k['name'])
або як запропонували JFSebastian та інші,
from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name'))
Для повноти (як зазначено у коментарях fitzgeraldsteele) додайте reverse=True
до сортування за спаданням
newlist = sorted(l, key=itemgetter('name'), reverse=True)
itemgetter(i)
де i
індекс елемента кортежа для сортування.
itemgetter
приймає більше ніж один аргумент: itemgetter(1,2,3)
це функція, яка повертає кортеж на зразок obj[1], obj[2], obj[3]
, тож ви можете використовувати його для виконання складних сортів.
import operator
Сортувати список словників за ключем = 'ім'я':
list_of_dicts.sort(key=operator.itemgetter('name'))
Сортувати список словників за ключем = 'age':
list_of_dicts.sort(key=operator.itemgetter('age'))
key=lambda k: (k['name'], k['age'])
. (або key=itemgetter('name', 'age')
). кортежі cmp
порівнюватимуть кожен елемент по черзі. це криваво блискуче.
key
аргумент для list.sort()
не описаний. Будь-яка ідея, де це знайти?
list
друзів.
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.
Якщо ви хочете сортувати список за кількома клавішами, ви можете зробити наступне:
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']))
Це досить хакітсько, оскільки він покладається на перетворення значень в єдине представлення рядків для порівняння, але працює так, як очікувалося, для чисел, включаючи негативні (хоча вам потрібно буде правильно відформатувати рядок з нульовими прокладками, якщо ви використовуєте числа)
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'])
Я думаю, ви мали на увазі:
[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
Це було б відсортовано так:
sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))
Ви можете використовувати спеціальну функцію порівняння або передати функцію, яка обчислює спеціальний ключ сортування. Зазвичай це більш ефективно, оскільки ключ обчислюється лише один раз на предмет, тоді як функція порівняння буде називатися набагато більше разів.
Ви можете це зробити так:
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'))
Використовуючи трансформацію Шварца з 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, яка використовується для підвищення ефективності сортування списку елементів. Ця ідіома підходить для сортування на основі порівняння, коли впорядкування фактично засноване на впорядкуванні певного властивості (ключа) елементів, де обчислення цього властивості - це інтенсивна операція, яку слід виконувати мінімально кілька разів. Трансформація Шварца відрізняється тим, що вона не використовує названі тимчасові масиви.
key=
for .sort
2.4 з 2004 року, тобто 2004 рік, він робить трансформацію Шварца в межах сортувального коду в C; таким чином, цей метод корисний лише на Pythons 2.0-2.3. всім яким більше 12 років.
Ви повинні реалізувати власну функцію порівняння, яка буде порівнювати словники за значеннями клавіш імен. Див. Сортування міні-КАК ДО з PythonInfo Wiki
колись нам потрібно скористатися, 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}]
Ось альтернативне загальне рішення - воно сортує елементи дикту за ключами та значеннями. Перевага його - не потрібно вказувати ключі, і все одно він буде працювати, якщо в деяких словниках відсутні ключі.
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
Якщо вам не потрібен оригінал 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}]
Скажімо, у мене 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
Перевірте це .
Я був великим шанувальником фільтру з лямбда, однак це не найкращий варіант, якщо враховувати складність часу
Перший варіант
sorted_list = sorted(list_to_sort, key= lambda x: x['name'])
# returns list of values
Другий варіант
list_to_sort.sort(key=operator.itemgetter('name'))
#edits the list, does not return a new list
Швидке порівняння exec часів
# 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 петель, найкраще 3: 0,736 використання в циклі
# 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 петель, найкраще 3: 0,438 використання в циклі
Якщо продуктивність викликає занепокоєння, я б використовував operator.itemgetter
замість того, lambda
як вбудовані функції виконують швидше, ніж ручні функції. itemgetter
Здається, ця функція виконує приблизно на 20% швидше, ніж lambda
на основі мого тестування.
З https://wiki.python.org/moin/PythonSpeed :
Аналогічно, вбудовані функції працюють швидше, ніж вбудовані вручну еквіваленти. Наприклад, map (operator.add, v1, v2) швидше, ніж map (лямбда x, y: x + y, v1, v2).
Ось порівняння сортування швидкості , використовуючи lambda
проти 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 same sort order
sorted(l, key=lambda x: x['name']) == sorted(l, key=operator.itemgetter('name'))
True
Обидві методи сортують список в одному порядку (перевіряється виконанням остаточного висловлювання в кодовому блоці), але одна трохи швидша.
[{'name':'Bart', 'age':10, 'note':3},{'name':'Homer','age':10,'note':2},{'name':'Vasile','age':20,'note':3}]
І використовувати:from operator import itemgetter newlist = sorted(old_list, key=itemgetter(-'note','name')
EDIT: Тестовано, і він працює, але я не знаю, як зробити зауваження DESC та назву ASC.