a

Câu hỏi Làm cách nào để sắp xếp từ điển theo giá trị?


Tôi có một từ điển các giá trị được đọc từ hai trường trong cơ sở dữ liệu: một trường chuỗi và một trường số. Trường chuỗi là duy nhất, vì vậy đó là chìa khóa của từ điển.

Tôi có thể sắp xếp trên các phím, nhưng làm thế nào tôi có thể sắp xếp dựa trên các giá trị?

Lưu ý: Tôi đã đọc câu hỏi Stack Overflow Làm cách nào để sắp xếp danh sách từ điển theo giá trị của từ điển bằng Python? và có lẽ có thể thay đổi mã của tôi để có danh sách các từ điển, nhưng vì tôi không thực sự cần một danh sách từ điển tôi muốn biết nếu có một giải pháp đơn giản hơn.


2938
2018-03-05 00:49


gốc


Cấu trúc dữ liệu từ điển không có thứ tự vốn có. Bạn có thể lặp qua nó nhưng không có gì để đảm bảo rằng việc lặp lại sẽ theo bất kỳ thứ tự cụ thể nào. Điều này là do thiết kế, do đó, đặt cược tốt nhất của bạn là probaly sử dụng cấu trúc dữ liệu anohter để biểu diễn. - Daishiman
"Sắp xếp ()" có thể hoạt động trên các từ điển (và trả về một danh sách các khóa được sắp xếp), vì vậy tôi nghĩ rằng anh ta biết điều này. Nếu không biết chương trình của mình, thật vô lý khi nói với ai đó rằng họ đang sử dụng cấu trúc dữ liệu sai. Nếu tra cứu nhanh là những gì bạn cần 90% thời gian, sau đó một dict có lẽ là những gì bạn muốn. - bobpaul
Đối với những người cho rằng đây là bản sao của stackoverflow.com/questions/72899/… , câu hỏi đó được đánh dấu là bản sao của câu hỏi này. - Marcin
Nếu có thể, hãy tạo một NumPy Series từ từ điển và sắp xếp nó bằng cách sử dụng pandas.Series.order - Dror
Tất cả ba kết quả đầu ra (khóa, giá trị, cả hai) để sắp xếp từ điển đều được đề cập ở đây theo một phong cách rõ ràng và súc tích: stackoverflow.com/questions/16772071/sort-dict-by-value-python - JStrahl


Các câu trả lời:


Không thể sắp xếp một từ điển, chỉ để có được một đại diện của một từ điển được sắp xếp. Từ điển vốn dĩ không có thứ tự, nhưng các loại khác, chẳng hạn như danh sách và bộ dữ liệu, thì không. Vì vậy, bạn cần một kiểu dữ liệu được sắp xếp để biểu diễn các giá trị đã sắp xếp, đây sẽ là một danh sách - có thể là một danh sách các bộ dữ liệu.

Ví dụ,

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))

sorted_x sẽ là danh sách các bộ dữ liệu được sắp xếp theo phần tử thứ hai trong mỗi bộ dữ liệu. dict(sorted_x) == x.

Và đối với những người muốn sắp xếp trên các khóa thay vì các giá trị:

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))

Trong Python3 kể từ khi giải nén không được phép [1] chúng ta có thể sử dụng

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_by_value = sorted(x.items(), key=lambda kv: kv[1])

3555
2018-03-05 00:59



cho thời gian trên các phân loại từ điển khác nhau theo lược đồ giá trị: writeonly.wordpress.com/2008/08/30/… - Gregg Lind
sorted_x.reverse() sẽ cho bạn một thứ tự giảm dần (bởi phần tử tuple thứ hai) - saidimu apale
saidimu: Vì chúng tôi đã sử dụng sorted(), nó hiệu quả hơn để vượt qua reverse=True tranh luận. - rmh
Trong python3 tôi đã sử dụng lambda: sorted(d.items(), key=lambda x: x[1]). Điều này sẽ làm việc trong python 2.x? - Keyo
OrderedDict được thêm vào bộ sưu tập trong 2.7. Ví dụ sắp xếp được hiển thị tại: docs.python.org/library/… - monkut


Đơn giản như: sorted(dict1, key=dict1.get)

Vâng, nó thực sự có thể làm một "sắp xếp theo giá trị từ điển". Gần đây tôi đã phải làm điều đó trong một câu hỏi về Golf Stack (Stack Overflow) Mã sân golf: Biểu đồ tần số từ). Tóm tắt, vấn đề là loại: đưa ra một văn bản, đếm tần suất mỗi từ được gặp phải và hiển thị một danh sách các từ trên cùng, được sắp xếp theo tần suất giảm.

Nếu bạn xây dựng một từ điển với các từ như khóa và số lần xuất hiện của mỗi từ dưới dạng giá trị, được đơn giản hóa ở đây dưới dạng:

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
  d[w] += 1

sau đó bạn có thể nhận được một danh sách các từ, được sắp xếp theo tần suất sử dụng với sorted(d, key=d.get) - sắp xếp lặp lại qua các phím từ điển, sử dụng số lần xuất hiện từ như một phím sắp xếp.

for w in sorted(d, key=d.get, reverse=True):
  print w, d[w]

Tôi đang viết giải thích chi tiết này để minh họa những gì mọi người thường nói "Tôi có thể dễ dàng sắp xếp từ điển theo khóa, nhưng làm cách nào để sắp xếp theo giá trị" - và tôi nghĩ OP đang cố giải quyết vấn đề như vậy. Và giải pháp là làm loại danh sách các khóa, dựa trên các giá trị, như được hiển thị ở trên.


969
2017-07-05 08:01



Điều này cũng tốt nhưng key=operator.itemgetter(1) nên có khả năng mở rộng hơn cho hiệu quả hơn key=d.get - smci
Trước tiên, bạn cần: nhập bộ sưu tập # để sử dụng defaultdict - rjurney
@raylu Tôi quan sát hành vi "không hoạt động" bằng cách sử dụng itemgetter: ----- from operator import itemgetter d = {"a":7, "b":1, "c":5, "d":3} sorted_keys = sorted(d, key=itemgetter, reverse=True) for key in sorted_keys: print "%s: %d" % (key, d[key])  ----- -> b: 1 c: 5 a: 7 d: 3 Kết quả thay đổi mỗi khi tôi chạy mã: lạ. (xin lỗi, không thể lấy mã để hiển thị đúng) - bli
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True) và for key, val in sorted_keys: print "%s: %d" % (key, val) - itemgetter tạo ra một hàm khi nó được gọi, bạn không sử dụng nó trực tiếp như trong ví dụ của bạn. Và một phép lặp đơn giản trên một dict sử dụng các khóa không có các giá trị - Izkata
tôi đã đến từ tương lai để nói với bạn về collections.Counter, có một most_common phương pháp mà bạn có thể quan tâm :) - Eevee


Bạn đã có thể sử dụng:

sorted(d.items(), key=lambda x: x[1])

Điều này sẽ sắp xếp từ điển theo các giá trị của mỗi mục trong từ điển từ nhỏ nhất đến lớn nhất.


607
2018-02-13 16:33



1 Để trở thành giải pháp sạch nhất. Tuy nhiên, nó không sắp xếp từ điển (bảng băm, không thể), thay vào đó nó trả về một danh sách theo thứ tự (key, value) tuples. - Keyo
@Keyo Tôi mới làm quen với python và bắt gặp sự cần thiết phải sắp xếp một từ điển. Và tôi muốn chắc chắn rằng tôi hiểu rõ bạn: không có cách nào để sử dụng lambda để sắp xếp một từ điển, phải không? - lv10
Tôi thích key=lambda (k, v): v cá nhân - Claudiu
@Claudiu Tôi thích điều đó (k, v) cú pháp quá, nhưng nó không có sẵn trong Python 3, giải nén thông số tuple đã xóa bỏ. - Bob Stein
@Nyxynyx Chỉ cần thêm reverse=True bên trong bit được sắp xếp (tức là sorted(a.items(), key=lambda x: x[1], reverse=True)) - Mathime


Dicts không thể được sắp xếp, nhưng bạn có thể xây dựng một danh sách được sắp xếp từ chúng.

Danh sách các giá trị dict được sắp xếp:

sorted(d.values())

Một danh sách các cặp (khóa, giá trị), được sắp xếp theo giá trị:

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))

165
2018-03-05 01:05



+1: sắp xếp (d.values ​​()) dễ đọc / dễ hiểu hơn so với sắp xếp của Nas (dict1, key = dict1.get), và do đó nhiều Pythonic hơn. Về khả năng đọc, vui lòng xem xét namedtuple gợi ý. - Remi
Thứ tự nào là các khóa có cùng giá trị được đặt trong? Trước tiên, tôi đã sắp xếp danh sách theo các khóa, sau đó theo giá trị, nhưng thứ tự của các khóa có cùng giá trị không còn. - SabreWolfy
@ Remi, đó là hai thứ khác nhau! sorted(d.values()) trả về danh sách được sắp xếp của giá trị từ điển, nơi sorted(d, key=d.get) trả về danh sách của phím, được sắp xếp theo thứ tự các giá trị! Cách khác. Nếu bạn không thấy sự cần thiết cho thứ hai, hãy đọc bài đăng của tôi ở trên cho ví dụ "cuộc sống thực" - Nas Banov


Trong Python 2.7 gần đây, chúng ta có OrderedDict loại, ghi nhớ thứ tự các mục được thêm vào.

>>> d = {"third": 3, "first": 1, "fourth": 4, "second": 2}

>>> for k, v in d.items():
...     print "%s: %s" % (k, v)
...
second: 2
fourth: 4
third: 3
first: 1

>>> d
{'second': 2, 'fourth': 4, 'third': 3, 'first': 1}

Để tạo từ điển đặt hàng mới từ bản gốc, sắp xếp theo các giá trị:

>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

OrderedDict hoạt động như một dict bình thường:

>>> for k, v in d_sorted_by_value.items():
...     print "%s: %s" % (k, v)
...
first: 1
second: 2
third: 3
fourth: 4

>>> d_sorted_by_value
OrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])

128
2017-07-05 02:50



Đây không phải là những gì câu hỏi là về - nó không phải là về duy trì thứ tự của các phím nhưng về "phân loại theo giá trị" - Nas Banov
@Nas Banov: nó KHÔNG được phân loại theo khóa. nó sắp xếp theo thứ tự, chúng ta tạo ra các vật phẩm. trong trường hợp của chúng ta, chúng ta sắp xếp theo giá trị. Thật không may, 3-mục dict đã không may được lựa chọn để thứ tự là như nhau, khi được sắp xếp voth theo giá trị và chìa khóa, vì vậy tôi mở rộng dict mẫu. - mykhal
sorted(d.items(), key=lambda x: x[1]) Bạn có thể giải thích những gì x có nghĩa là, tại sao nó có thể x[1] để lambda? Tại sao nó không thể x[0]? Cảm ơn nhiều! - JZAU
@jie d.items() trả về một danh sách các cặp khóa / giá trị từ từ điển và x là một phần tử của bộ dữ liệu này. x[0] sẽ là chìa khóa và x[1] sẽ là giá trị. Khi chúng tôi dự định sắp xếp giá trị, chúng tôi sẽ vượt qua x[1] đến lambda. - CadentOrange
@Boern d.items() trả về một vùng chứa danh sách giống như (key, value) tuples. [0] truy cập phần tử đầu tiên của tuple - khóa - và [1] truy cập phần tử thứ hai - giá trị. - BallpointBen


CẬP NHẬT: Ngày 5 tháng 12 năm 2015 sử dụng Python 3.5

Trong khi tôi tìm thấy câu trả lời được chấp nhận hữu ích, tôi cũng ngạc nhiên rằng nó chưa được cập nhật để tham khảo OrderedDict từ thư viện chuẩn bộ sưu tập mô-đun như một giải pháp khả thi, hiện đại - được thiết kế để giải quyết chính xác loại vấn đề này.

from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

Chính thức OrderedDict tài liệu cung cấp một ví dụ rất giống nhau, nhưng sử dụng một lambda cho hàm sắp xếp:

# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
# OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

75
2017-12-05 09:46





Nó thường có thể rất tiện dụng để sử dụng namedtuple. Ví dụ: bạn có từ điển 'tên' làm khóa và 'điểm' làm giá trị và bạn muốn sắp xếp theo 'điểm':

import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

sắp xếp với điểm số thấp nhất trước tiên:

worst = sorted(Player(v,k) for (k,v) in d.items())

sắp xếp với số điểm cao nhất đầu tiên:

best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)

Bây giờ bạn có thể lấy tên và điểm số, giả sử người chơi thứ hai tốt nhất (index = 1) rất giống như thế này:

player = best[1]
player.name
    'Richard'
player.score
    7

64
2017-08-30 00:30



Làm thế nào tôi có thể chuyển nó trở lại từ điển? - rowana
as_list = [Player (v, k) cho (k, v) trong d.items ()] as_dict = dict ((p.name, p.score) cho p trong as_list) - Remi


Khá giống như câu trả lời của Hank Gay;


    được sắp xếp ([(giá trị, khóa) cho (khóa, giá trị) trong mydict.items ()])

Hoặc được tối ưu hóa một chút theo gợi ý của John Fouhy;


    được sắp xếp ((giá trị, khóa) cho (khóa, giá trị) trong mydict.items ())


57
2018-03-05 01:06



..và như với câu trả lời của Hank Gay, bạn không cần các dấu ngoặc vuông. sắp xếp () sẽ vui vẻ thực hiện bất kỳ lặp lại nào, chẳng hạn như biểu thức trình tạo. - John Fouhy
Bạn vẫn có thể cần trao đổi các phần tử (giá trị, khóa) tuple để kết thúc bằng (khóa, giá trị). Một danh sách hiểu khác là cần thiết. [(key, value) for (value, key) in sorted_list_of_tuples] - saidimu apale
không, tốt hơn là bỏ dấu ngoặc vuông, bởi vì sorted sẽ phải xây dựng lại danh sách, và xây dựng lại từ gencomp sẽ nhanh hơn. Tốt cho codegolfing, xấu cho tốc độ. Giữ xấu xí ([]) phiên bản. - Jean-François Fabre


Kể từ Python 3.6 được xây dựng trong dict sẽ được đặt hàng

Tin tốt, do đó, trường hợp sử dụng ban đầu của các cặp ánh xạ được truy xuất từ ​​cơ sở dữ liệu với các chuỗi chuỗi duy nhất như các khóa và giá trị số dưới dạng các giá trị được xây dựng trong Python v3.6 + dict, bây giờ nên tôn trọng thứ tự chèn.

Nếu nói các biểu thức bảng hai cột kết quả từ một truy vấn cơ sở dữ liệu như:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

sẽ được lưu trữ trong hai tuples Python, k_seq và v_seq (được căn chỉnh theo chỉ mục số và với cùng độ dài của khóa học), sau đó:

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

Cho phép xuất sau này như sau:

for k, v in ordered_map.items():
    print(k, v)

năng suất trong trường hợp này (đối với dict được xây dựng trong Python 3.6+ mới!):

foo 0
bar 1
baz 42

trong cùng một thứ tự cho mỗi giá trị của v.

Trong Python 3.5 cài đặt trên máy tính của tôi, nó hiện sản lượng:

bar 1
foo 0
baz 42

Chi tiết:

Theo đề xuất vào năm 2012 bởi Raymond Hettinger (xem thư trên python-dev với chủ đề "Từ điển nhỏ gọn hơn với lặp lại nhanh hơn") và bây giờ (trong năm 2016) đã công bố trong một bức thư của Victor Stinner để python-dev với chủ đề "Python 3.6 dict trở nên nhỏ gọn và nhận được một phiên bản riêng tư, và các từ khóa được đặt hàng" do việc sửa chữa / thi hành vấn đề 27350 "Nhỏ gọn và ra lệnh dict" trong Python 3.6, bây giờ chúng ta có thể sử dụng một dict tích hợp để duy trì thứ tự chèn !!

Hy vọng rằng điều này sẽ dẫn đến việc thực hiện lớp OrderedDict mỏng như một bước đầu tiên. Như @ JimFasarakis-Hilliard đã chỉ ra, một số trường hợp sử dụng cho loại OrderedDict cũng trong tương lai. Tôi nghĩ rằng cộng đồng Python lớn sẽ kiểm tra cẩn thận, nếu điều này sẽ đứng kiểm tra thời gian, và những gì các bước tiếp theo sẽ được.

Thời gian để suy nghĩ lại thói quen viết mã của chúng tôi để không bỏ lỡ những khả năng được mở theo thứ tự ổn định của:

  • Đối số từ khóa và
  • (lưu trữ dict trung gian)

Việc đầu tiên bởi vì nó giảm bớt công văn trong việc thực hiện các chức năng và phương pháp trong một số trường hợp.

Thứ hai là nó khuyến khích để dễ dàng sử dụng hơn dicts là lưu trữ trung gian trong các đường ống xử lý.

Raymond Hettinger vui lòng cung cấp tài liệu giải thích "Tech Behind Python 3.6 Từ điển"- từ buổi thuyết trình Nhóm Gặp gỡ Python của San Francisco 2016-DEC-08.

Và có thể một số trang câu hỏi và trả lời được trang trí cao Stack Overflow sẽ nhận được các biến thể của thông tin này và nhiều câu trả lời chất lượng cao sẽ yêu cầu bản cập nhật cho mỗi phiên bản.

Caveat Emptor (nhưng cũng thấy bên dưới cập nhật 2017-12-15):

Như @ajcr lưu ý đúng: "Khía cạnh bảo toàn thứ tự của việc triển khai mới này được coi là chi tiết triển khai và không nên dựa vào." (từ whatsnew36) không hái nit, nhưng trích dẫn đã được cắt một chút bi quan ;-). Nó tiếp tục là "(điều này có thể thay đổi trong tương lai, nhưng mong muốn có triển khai dict mới này trong ngôn ngữ cho một vài bản phát hành trước khi thay đổi đặc tả ngôn ngữ để ủy nhiệm ngữ nghĩa bảo quản trật tự cho tất cả các triển khai Python hiện tại và tương lai; giúp duy trì khả năng tương thích ngược với các phiên bản cũ của ngôn ngữ mà thứ tự lặp ngẫu nhiên vẫn có hiệu lực, ví dụ như Python 3.5). "

Vì vậy, như trong một số ngôn ngữ của con người (ví dụ: tiếng Đức), việc sử dụng định dạng ngôn ngữ và giờ đây sẽ được tuyên bố ... trong whatsnew36.

Cập nhật 2017-12-15:

Trong một thư đến danh sách python-dev, Guido van Rossum tuyên bố:

Làm cho nó như vậy. "Dict giữ trật tự chèn" là phán quyết. Cảm ơn!

Vì vậy, phiên bản 3.6 CPython tác dụng phụ của việc đặt hàng chèn dict giờ đây đã trở thành một phần của đặc tả ngôn ngữ (và không chỉ là một chi tiết thực hiện). Chủ đề thư đó cũng nổi lên một số mục tiêu thiết kế phân biệt cho collections.OrderedDict theo lời nhắc của Raymond Hettinger trong cuộc thảo luận.


48
2017-09-10 10:05



Cảnh báo trên trang 'whatsnew' bạn đã liên kết cần được nhấn mạnh: khía cạnh bảo quản trật tự của triển khai mới này được coi là chi tiết triển khai và không nên dựa vào. Không ai nên giả định rằng dict loại sẽ tôn trọng thứ tự chèn trong mã của chúng. Đây không phải là một phần của định nghĩa của ngôn ngữ và việc thực hiện có thể thay đổi trong bất kỳ bản phát hành nào trong tương lai. Tiếp tục sử dụng OrderedDict để đảm bảo trật tự. - Alex Riley
@ajcr cảm ơn cho caveat, rất đánh giá cao - như mặt cười và có thể đã được dệt vào phản ứng của tôi, nên chỉ ra, sự thay đổi là lớn nhưng tất nhiên, chỉ có sẵn cho CPython (tham khảo thực hiện) và PyPy. Đối với một cái gì đó hoàn toàn khác nhau ... Tôi hiếm khi nói chuyện với chi tiết không thực hiện khi mã hóa hướng dẫn người-máy. Nếu nó chỉ là Jython ;-) ... tôi có thể không có can đảm để viết nó. - Dilettant
OrderedDict chắc chắn sẽ không bị bỏ; thay vào đó, nó sẽ trở thành một wrapper mỏng xung quanh việc thực hiện dict hiện tại (vì vậy bạn có thể thêm rằng nó sẽ trở nên nhỏ gọn hơn). Thêm đoạn mã đó bằng ImportError không phải là ý tưởng hay nhất vì nó gây hiểu nhầm cho độc giả OrderedDict không sử dụng. - Jim Fasarakis Hilliard
@ JimFasarakis-Hilliard cảm ơn bạn đã phản hồi. "Những ý tưởng hay nhất" khiến tôi mỉm cười - tương lai thường khó dự đoán. Nhưng tôi thích đề nghị của bạn sẽ kiểm tra các nguồn, hãy thử nó và sau đó cập nhật câu trả lời cho phù hợp. Cảm ơn một lần nữa. - Dilettant
Để trả lời câu trả lời này và các câu lệnh có cấu trúc, tôi đã đăng một câu trả lời mới. Phản hồi chào mừng! - Bram Vanroy