Câu trả lời:
Nó có thể trông sạch hơn bằng cách sử dụng một phím thay vì cmp:
newlist = sorted(list_to_be_sorted, key=lambda k: k['name'])
hoặc như JFSebastian và những người khác đề xuất,
from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name'))
Để hoàn thiện (như được chỉ ra trong các nhận xét của fitzgeraldsteele), hãy thêm reverse=True
vào sắp xếp giảm dần
newlist = sorted(l, key=itemgetter('name'), reverse=True)
itemgetter(i)
mà i
là chỉ số của phần tử tuple để sắp xếp trên.
itemgetter
chấp nhận nhiều hơn một đối số: itemgetter(1,2,3)
là một hàm trả về một tuple như thế obj[1], obj[2], obj[3]
, vì vậy bạn có thể sử dụng nó để thực hiện các sắp xếp phức tạp.
import operator
Để sắp xếp danh sách từ điển theo key = 'name':
list_of_dicts.sort(key=operator.itemgetter('name'))
Để sắp xếp danh sách từ điển theo key = 'age':
list_of_dicts.sort(key=operator.itemgetter('age'))
key=lambda k: (k['name'], k['age'])
,. (hoặc key=itemgetter('name', 'age')
). tuple cmp
sẽ so sánh lần lượt từng yếu tố. đó là máu rực rỡ.
key
đối số tùy chọn list.sort()
không được mô tả. Bất cứ ý tưởng nơi để tìm thấy điều đó?
list
và bạn bè.
my_list = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
my_list.sort(lambda x,y : cmp(x['name'], y['name']))
my_list
bây giờ sẽ là những gì bạn muốn.
(3 năm sau) Đã chỉnh sửa để thêm:
Đối key
số mới là hiệu quả hơn và gọn gàng hơn. Một câu trả lời tốt hơn bây giờ trông như:
my_list = sorted(my_list, key=lambda k: k['name'])
... lambda là, IMO, dễ hiểu hơn operator.itemgetter
, nhưng YMMV.
Nếu bạn muốn sắp xếp danh sách theo nhiều khóa, bạn có thể làm như sau:
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']))
Nó khá là hackish, vì nó phụ thuộc vào việc chuyển đổi các giá trị thành một chuỗi đại diện để so sánh, nhưng nó hoạt động như mong đợi đối với các số bao gồm cả số âm (mặc dù bạn sẽ cần định dạng chuỗi của mình một cách phù hợp với số 0 nếu bạn đang sử dụng số)
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'])
Tôi đoán bạn có nghĩa là:
[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
Điều này sẽ được sắp xếp như thế này:
sorted(l,cmp=lambda x,y: cmp(x['name'],y['name']))
Bạn có thể sử dụng chức năng so sánh tùy chỉnh hoặc bạn có thể chuyển vào hàm tính toán khóa sắp xếp tùy chỉnh. Điều đó thường hiệu quả hơn vì khóa chỉ được tính một lần cho mỗi mục, trong khi chức năng so sánh sẽ được gọi nhiều lần hơn.
Bạn có thể làm theo cách này:
def mykey(adict): return adict['name']
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=mykey)
Nhưng thư viện chuẩn chứa một thói quen chung để lấy các mục của các đối tượng tùy ý : itemgetter
. Vì vậy, hãy thử điều này thay thế:
from operator import itemgetter
x = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age':10}]
sorted(x, key=itemgetter('name'))
Sử dụng biến đổi Schwartzian từ Perl,
py = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]
làm
sort_on = "name"
decorated = [(dict_[sort_on], dict_) for dict_ in py]
decorated.sort()
result = [dict_ for (key, dict_) in decorated]
cho
>>> result
[{'age': 10, 'name': 'Bart'}, {'age': 39, 'name': 'Homer'}]
Thông tin thêm về biến đổi Perl Schwartzian
Trong khoa học máy tính, biến đổi Schwartzian là một thành ngữ lập trình Perl được sử dụng để cải thiện hiệu quả của việc sắp xếp danh sách các mục. Thành ngữ này phù hợp để sắp xếp dựa trên so sánh khi thứ tự thực sự dựa trên thứ tự của một thuộc tính nhất định (khóa) của các phần tử, trong đó tính toán thuộc tính đó là một hoạt động chuyên sâu nên được thực hiện với số lần tối thiểu. Biến đổi Schwartzian đáng chú ý ở chỗ nó không sử dụng các mảng tạm thời được đặt tên.
key=
cho .sort
từ 2.4, đó là năm 2004, nó là Schwartzian chuyển đổi trong mã phân loại, trong C; do đó phương pháp này chỉ hữu ích trên Pythons 2.0-2.3. tất cả đều hơn 12 tuổi.
Bạn phải thực hiện chức năng so sánh của riêng mình để so sánh các từ điển theo các giá trị của các khóa tên. Xem Sắp xếp Mini-CÁCH ĐẾN từ PythonInfo Wiki
đôi khi chúng ta cần sử dụng lower()
ví dụ
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}]
Đây là giải pháp chung thay thế - nó sắp xếp các yếu tố của dict theo khóa và giá trị. Ưu điểm của nó - không cần chỉ định khóa và nó vẫn hoạt động nếu thiếu một số khóa trong một số từ điển.
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)
Sử dụng gói gấu trúc là một phương pháp khác, mặc dù thời gian chạy ở quy mô lớn chậm hơn nhiều so với các phương pháp truyền thống được đề xuất bởi người khác:
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()
Dưới đây là một số giá trị điểm chuẩn cho một danh sách nhỏ và một danh sách lớn (100k +) 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
Nếu bạn không cần bản gốc list
của dictionaries
, bạn có thể sửa đổi nó tại chỗ bằng sort()
phương thức sử dụng chức năng khóa tùy chỉnh.
Chức năng chính:
def get_name(d):
""" Return the value of a key in a dictionary. """
return d["name"]
Các list
để được sắp xếp:
data_one = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]
Sắp xếp nó tại chỗ:
data_one.sort(key=get_name)
Nếu bạn cần bản gốc list
, hãy gọi sorted()
hàm chuyển qua nó list
và hàm key, sau đó gán hàm được trả về được sắp xếp list
cho một biến mới:
data_two = [{'name': 'Homer', 'age': 39}, {'name': 'Bart', 'age': 10}]
new_data = sorted(data_two, key=get_name)
In ấn data_one
và new_data
.
>>> print(data_one)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
>>> print(new_data)
[{'name': 'Bart', 'age': 10}, {'name': 'Homer', 'age': 39}]
Hãy nói rằng tôi có một từ điển D
với các yếu tố dưới đây. Để sắp xếp chỉ cần sử dụng đối số khóa trong sắp xếp để truyền chức năng tùy chỉnh như dưới đây:
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
Kiểm tra này .
Tôi đã là một fan hâm mộ lớn của bộ lọc w / lambda tuy nhiên đó không phải là lựa chọn tốt nhất nếu bạn xem xét độ phức tạp của thời gian
Lựa chọn đầu tiên
sorted_list = sorted(list_to_sort, key= lambda x: x['name'])
# returns list of values
Sự lựa chọn thứ hai
list_to_sort.sort(key=operator.itemgetter('name'))
#edits the list, does not return a new list
So sánh nhanh thời gian thực hiện
# 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 vòng, tốt nhất là 3: 0,736 usec mỗi vòng
# 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 vòng, tốt nhất là 3: 0,438 usec mỗi vòng
Nếu hiệu suất là một mối quan tâm, tôi sẽ sử dụng operator.itemgetter
thay vì các lambda
hàm tích hợp thực hiện nhanh hơn các chức năng thủ công. Các itemgetter
chức năng dường như để thực hiện khoảng 20% nhanh hơn lambda
dựa trên thử nghiệm của tôi.
Từ https://wiki.python.org/moin/PythonSpeed :
Tương tự, các hàm dựng sẵn chạy nhanh hơn các hàm tương đương được làm bằng tay. Ví dụ: map (oper.add, v1, v2) nhanh hơn map (lambda x, y: x + y, v1, v2).
Dưới đây là một so sánh phân loại tốc độ sử dụng 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 same sort order
sorted(l, key=lambda x: x['name']) == sorted(l, key=operator.itemgetter('name'))
True
Cả hai kỹ thuật sắp xếp danh sách theo cùng một thứ tự (được xác minh bằng cách thực hiện câu lệnh cuối cùng trong khối mã) nhưng một kỹ thuật nhanh hơn một chút.
[{'name':'Bart', 'age':10, 'note':3},{'name':'Homer','age':10,'note':2},{'name':'Vasile','age':20,'note':3}]
Và sử dụng:from operator import itemgetter newlist = sorted(old_list, key=itemgetter(-'note','name')
EDIT: Đã thử nghiệm và nó đang hoạt động nhưng tôi không biết cách ghi chú DESC và đặt tên ASC.