Làm cách nào để sắp xếp một từ điển theo giá trị?


3422

Tôi có một từ điển các giá trị được đọc từ hai trường trong cơ sở dữ liệu: trường chuỗi và 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 các khóa, nhưng làm cách nào để sắp xếp dựa trên các giá trị?

Lưu ý: Tôi đã đọc câu hỏi Stack Overflow tại đây Làm cách nào để sắp xếp danh sách từ điển theo giá trị của từ điển? và có lẽ có thể thay đổi mã của tôi để có một danh sách 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 liệu có một giải pháp đơn giản hơn để sắp xếp theo thứ tự tăng dần hoặc giảm dần.


9
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 phép lặp sẽ tuân theo bất kỳ thứ tự cụ thể nào. Điều này là do thiết kế, vì vậy đặt cược tốt nhất của bạn là xác thực bằng cách sử dụng cấu trúc dữ liệu anohter để đại diện.
Daishiman

135
"sort ()" có thể hoạt động trên từ điển (và trả về danh sách các khóa được sắp xếp), vì vậy tôi nghĩ rằng anh ấy nhận thức được điều này. Không biết chương trình của anh ấy, thật vô lý khi nói với ai đó 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, thì một dict có lẽ là những gì bạn muốn.
bobpaul

Tất cả ba kết quả đầu ra (khóa, giá trị, cả hai) để sắp xếp từ điển được trình bày ở đây theo một kiểu rõ ràng và súc tích: stackoverflow.com/questions/16772071/sort-dict-by-value-python
JStrahl

2
@Daishiman Lớp cơ sở có thể không được đặt hàng nhưng OrderedDict là tất nhiên.
Taylor Edmiston

1
Trong từ điển Python 3.6+ giữ trật tự chèn. Tất nhiên, điều này không giống như khả năng sắp xếp chúng theo giá trị, nhưng mặt khác, không còn hợp lệ để nói rằng "cấu trúc dữ liệu từ điển không có thứ tự vốn có".
Konrad Kocik

Câu trả lời:


4950

Python 3.6+

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
{k: v for k, v in sorted(x.items(), key=lambda item: item[1])}
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

Python cũ hơn

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 đã không có trật 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ị được sắp xếp, đó 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à một danh sách các bộ dữ liệu được sắp xếp theo phần tử thứ hai trong mỗi bộ. 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 vì việc 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_x = sorted(x.items(), key=lambda kv: kv[1])

Nếu bạn muốn đầu ra là một dict, bạn có thể sử dụng collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)

43
để định thời gian cho việc sắp xếp từ điển khác nhau theo sơ đồ giá trị: writeonly.wordpress.com/2008/08/30/iêu
Gregg Lind

164
sorted_x.reverse()sẽ cung cấp cho bạn một thứ tự giảm dần (bởi yếu tố tuple thứ hai)
apimu apale

414
saidimu: Vì chúng tôi đã sử dụng sorted(), nên việc reverse=Truetranh luận sẽ hiệu quả hơn nhiều .
rmh

121
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

84
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/l Library / Kẻ
monkut

1263

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

Vâng, thực sự có thể thực hiện "sắp xếp theo các giá trị từ điển". Gần đây tôi đã phải làm điều đó trong Code Golf (Câu hỏi về Stack Overflow Code golf: Word tần số biểu đồ ). Tóm tắt, vấn đề thuộc loại: đưa ra một văn bản, đếm tần suất mỗi từ gặp phải và hiển thị danh sách các từ hàng đầu, đượ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ừ là khóa và số lần xuất hiện của mỗi từ dưới dạng giá trị, hãy đơn giản hóa ở đây là:

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 các khóa từ điển, sử dụng số lần xuất hiện từ làm khóa sắp xếp.

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

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


31
Điều này cũng tốt nhưng key=operator.itemgetter(1)nên có khả năng mở rộng hiệu quả hơnkey=d.get
smci

3
@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 cách)
bli

12
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True)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 mà không có các giá trị
Izkata

18
Tôi đến từ tương lai để nói với bạn collections.Counter, trong đó có một most_commonphương pháp có thể khiến bạn quan tâm :)
Eevee

2
@Eevee - có điều, nguy cơ bị hiểu lầm trong các bình luận ngắn không f2f. Amuzing tidbit: collections.Counterđã được thêm vào 2.7, được phát hành gần như đúng 7 năm trước! (Lúc đó tôi không biết về điều đó - cộng với việc tôi đã tránh nó trong môn đánh gôn với mục đích ngắn gọn, đó là nỗi ám ảnh duy nhất của trò chơi)
Nas Banov

858

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 từng mục trong từ điển từ nhỏ nhất đến lớn nhất.

Để sắp xếp nó theo thứ tự giảm dần, chỉ cần thêm reverse=True:

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

Đầu vào:

d = {'one':1,'three':3,'five':5,'two':2,'four':4}
a = sorted(d.items(), key=lambda x: x[1])    
print(a)

Đầu ra:

[('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]

Từ những gì tôi đã nhìn thấy ( docs.python.org/2/library/... ), có một lớp được gọi là OrderedDict có thể được sắp xếp và duy trì trật tự trong khi vẫn còn là một cuốn từ điển. Từ các ví dụ mã, bạn có thể sử dụng lambda để sắp xếp nó, nhưng tôi chưa từng thử nó một cách cá nhân: P
UsAndRufus

53
Tôi thích key=lambda (k, v): vcá nhân hơn
Claudiu

35
@Claudiu Tôi cũng thích (k, v)cú pháp đó, nhưng nó không có sẵn trong Python 3 nơi giải nén tham số tuple đã bị xóa.
Bob Stein

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

3
Không. Tạo ra một lệnh từ một danh sách các bộ dữ liệu được sắp xếp sẽ giết thứ tự một lần nữa ...
Jean-François Fabre

233

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.

Một danh sách sắp xếp các giá trị dict:

sorted(d.values())

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

Thứ tự nào là các khóa có cùng giá trị được đặt trong? Tôi đã sắp xếp danh sách theo các khóa trước, sau đó theo các giá trị, nhưng thứ tự của các khóa có cùng giá trị không còn.
SabreWolfy

1
Bây giờ có thể sắp xếp các ký tự, bắt đầu với CPython 3.6 và tất cả các triển khai Python khác bắt đầu bằng 3.7
Boris

161

Trong Python 2.7 gần đây, chúng ta có loại OrderedDict mớ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 một từ điển được đặ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)])

5
Đây không phải là câu hỏi về vấn đề gì - không phải là về việc duy trì trật tự các khóa mà là về "sắp xếp theo giá trị"
Nas Banov

10
@Nas Banov: nó KHÔNG được sắp xếp theo khóa. nó được sắp xếp theo thứ tự, chúng tôi tạo ra các mục. trong trường hợp của chúng tôi, chúng tôi sắp xếp theo giá trị. Thật không may, dict 3 mục không may được chọn vì vậy thứ tự là như nhau, khi được sắp xếp voth theo giá trị và 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ì xcó nghĩa là, tại sao nó có thể đưa x[1]đến lambda? Tại sao nó không thể x[0]? Cảm ơn rât nhiều!
JZAU

1
@Boern d.items()trả về một bộ chứa các (key, value)bộ dữ liệu giống như danh sách . [0]truy cập phần tử đầu tiên của bộ dữ liệu - khóa - và [1]truy cập phần tử thứ hai - giá trị.
BallpointBen

2
Lưu ý: Kể từ 3.6 (như chi tiết triển khai CPython / PyPy) và kể từ 3.7 (dưới dạng bảo đảm ngôn ngữ Python), đồng bằng dictcũng được chèn theo thứ tự, vì vậy bạn chỉ có thể thay thế OrderedDictbằng dictmã chạy trên Python hiện đại. OrderedDictkhông thực sự cần thiết nữa trừ khi bạn cần sắp xếp lại thứ tự của một hiện tại dict(với move_to_end/ popitem) hoặc cần so sánh bình đẳng để nhạy cảm với trật tự. Nó sử dụng nhiều bộ nhớ hơn đơn giản dict, vì vậy nếu bạn có thể, dictlà cách để đi.
ShadowRanger

104

CẬP NHẬT: 5 THÁNG 12 NĂM 2015 bằng Python 3.5

Mặc dù tôi 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ừ mô-đun bộ sưu tập thư viện tiêu chuẩn như một giải pháp thay thế hiện đại, khả thi - đượ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)])

Tài liệu OrderedDict chính thức cũng cung cấp một ví dụ rất giống nhau, nhưng sử dụng lambda cho chức năng 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)])

86

Khá giống với câu trả lời của Hank Gay :

sorted([(value,key) for (key,value) in mydict.items()])

Hoặc tối ưu hóa một chút theo đề xuất của John Fouhy:

sorted((value,key) for (key,value) in mydict.items())

9
.. và như với câu trả lời của Hank Gay, bạn không cần dấu ngoặc vuông. sort () sẽ vui vẻ nhận bất kỳ lần lặp 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ử tuple (giá trị, khóa) để kết thúc với (khóa, giá trị). Một sự hiểu biết danh sách sau đó là cần thiết. [(key, value) for (value, key) in sorted_list_of_tuples]
saidimu apale

không, tốt hơn hết là để lại dấu ngoặc vuông, vì sorteddù sao cũng sẽ phải xây dựng lại danh sách và việc xây dựng lại từ gencomp sẽ nhanh hơn. Tốt cho codegolfing, xấu cho tốc độ. Giữ ([])phiên bản xấu xí .
Jean-François Fabre

75

Nó thường có thể rất tiện dụng để sử dụng têntuple . Ví dụ: bạn có một 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 thấp nhất trước:

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

sắp xếp với số điểm cao nhất trước:

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

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

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

Làm thế nào tôi có thể chuyển đổi nó trở lại một từ điển?
rowana

as_list = [Người chơi (v, k) cho (k, v) trong d.items ()] as_dict = dict ((p.name, p.score) cho p trong as_list)
Remi

72

Kể từ Python 3.6 , dict tích hợp sẽ được đặt hàng

Tin tốt, vì vậy, trường hợp sử dụng ban đầu của các cặp ánh xạ được lấy từ cơ sở dữ liệu với id chuỗi duy nhất là khóa và giá trị số dưới dạng giá trị thành một lệnh Python v3.6 + tích hợp, giờ đây phải tuân theo thứ tự chèn.

Nếu nói kết quả hai biểu thức bảng cột 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 bộ dữ liệu Python, k_seq và v_seq (được căn chỉnh theo chỉ số bằng 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 như:

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

mang lại hiệu quả trong trường hợp này (đối với dict tích hợp 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.

Trường hợp cài đặt Python 3.5 trên máy của tôi hiện tại nó mang lại:

bar 1
foo 0
baz 42

Chi tiết:

Như đề 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 tốc độ lặp nhanh hơn" ) và bây giờ (năm 2016) đã thông báo trong thư của Victor Stinner gửi python-dev với chủ đề "Python 3.6 dict trở thành nhỏ gọn và có phiên bản riêng tư và các từ khóa được đặt hàng " do việc khắc phục / thực hiện vấn đề 27350 " Dict và ra lệnh " trong Python 3.6, giờ đây chúng ta sẽ có thể sử dụng một lệnh chính tả tích hợp để duy trì trật tự chèn !!

Hy vọng rằng điều này sẽ dẫn đến việc thực hiện OrderedDict lớp mỏng như 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 nói chung sẽ kiểm tra cẩn thận, nếu điều này sẽ đứng trước thử thách của thời gian, và các bước tiếp theo sẽ là gì.

Đã đến lúc suy nghĩ lại về thói quen mã hóa của chúng tôi để không bỏ lỡ các khả năng được mở bằng cách đặt hàng ổn định:

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

Việc đầu tiên bởi vì nó dễ dàng gửi đi 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 vì nó khuyến khích sử dụng dễ dàng hơn dictnhư là lưu trữ trung gian trong xử lý đường ống.

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

Và có thể một số trang câu hỏi và câu trả lời được trang trí cao của 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 cũng sẽ yêu cầu cập nhật mỗi phiên bản.

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

Như @ajcr lưu ý chính xác: "Khía cạnh giữ trật tự của việc triển khai mới này được coi là một chi tiết thực hiện và không nên dựa vào." (từ whatsnew36 ) không chọn nit, nhưng trích dẫn đã bị cắt giảm 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ó bản triển khai chính tả mới này bằng ngôn ngữ cho một vài bản phát hành trước khi thay đổi thông số ngôn ngữ để bắt buộc ngữ nghĩa duy trì 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ũ hơn của ngôn ngữ trong đó thứ tự lặp ngẫu nhiên vẫn còn hiệu lực, ví dụ 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 hình ngôn ngữ và ý chí hiện đã được tuyên bố ... trong whatsnew36 .

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

Trong thư gửi đế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, hiệu ứng phụ CPython phiên bản 3.6 của thứ tự chèn dict hiện đang trở thành một phần của thông số ngôn ngữ (và không chỉ là một chi tiết triển khai). Chủ đề thư đó cũng nổi lên một số mục tiêu thiết kế khác biệt collections.OrderedDictnhư được nhắc nhở bởi Raymond Hettinger trong khi thảo luận.


15
Cảnh báo trên trang 'whatsnew' mà bạn đã liên kết nên được nhấn mạnh: khía cạnh giữ trật tự của việc triển khai mới này được coi là một chi tiết thực hiện và không nên dựa vào . Không ai nên cho rằng dictloại sẽ tôn trọng thứ tự chèn trong mã của họ. Đây không phải là một phần của định nghĩa ngôn ngữ và việc triển khai 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 vì sự cảnh báo, rất cảm kích - vì mặt cười và có thể đã được đưa vào phản ứng của tôi, những điều này nên chỉ ra, sự thay đổi là rất lớn nhưng tất nhiên, chỉ có sẵn cho CPython (triển khai tham chiếu) và PyPy. Đối với một cái gì đó hoàn toàn khác ... Tôi hiếm khi nói chuyện với các chi tiết không thực hiện khi mã hóa các hướng dẫn máy móc. Nếu đó chỉ là Jython ;-) ... Tôi có thể không đủ can đảm để viết nó.
Pha loãng

OrderedDictchắc chắn sẽ không bị bỏ rơi; thay vào đó, nó sẽ trở thành một trình bao bọc mỏng xung quanh việc triển khai chính tả hiện tại (vì vậy bạn có thể thêm rằng nó cũng sẽ trở nên gọn hơn). Thêm đoạn trích đó với ImportErrorý tưởng không hoàn toàn tốt nhất do nó gây hiểu lầm cho những người đọc OrderedDictkhông sử dụng.
Dimitris Fasarakis Hilliard

@ JimFasarakis-Hilliard cảm ơn bạn đã phản hồi. "Khá nhiều ý 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 đề xuất của bạn sẽ kiểm tra các nguồn, 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.
Pha loãng

8
@AlexRiley Sự cảnh báo này không còn chính xác. Python3.7 đảm bảo từ điển được đặt hàng.
gerrit

42

Tôi đã có cùng một vấn đề, và tôi đã giải quyết nó như thế này:

WantedOutput = sorted(MyDict, key=lambda x : MyDict[x]) 

(Những người trả lời "Không thể sắp xếp một lệnh" không đọc câu hỏi! Thực tế, "Tôi có thể sắp xếp các khóa, nhưng làm thế nào tôi có thể sắp xếp dựa trên các giá trị?" Rõ ràng có nghĩa là anh ta muốn có một danh sách các khóa được sắp xếp theo giá trị của các giá trị của chúng.)

Xin lưu ý rằng thứ tự không được xác định rõ (các khóa có cùng giá trị sẽ theo thứ tự tùy ý trong danh sách đầu ra).


1
Bạn đang thiếu giá trị từ kết quả
Dejell

Lưu ý rằng bạn vừa lặp lại từ điển và tìm nạp các giá trị bằng khóa của chúng, vì vậy hiệu suất khôn ngoan đây không phải là một giải pháp tối ưu.
Ron Klein

1
@Dejell: như người đóng góp nói, anh ta giải thích câu hỏi là "tôi có thể lấy danh sách các khóa được sắp xếp theo các giá trị không". Chúng tôi không cần các giá trị trong kết quả, chúng tôi có chúng trong từ điển.
Tối đa

36

Nếu các giá trị là số bạn cũng có thể sử dụng Countertừ các bộ sưu tập .

from collections import Counter

x = {'hello': 1, 'python': 5, 'world': 3}
c = Counter(x)
print(c.most_common())

>> [('python', 5), ('world', 3), ('hello', 1)]    

Nếu từ điển của bạn là gì >>> x = {'xin chào': 1, 'trăn': 5, 'thế giới': 300}
James Sapam

@yopy Counter({'hello':1, 'python':5, 'world':300}).most_common()cho [('world', 300), ('python', 5), ('hello', 1)]. Điều này thực sự hoạt động đối với bất kỳ loại giá trị có thể sắp xếp nào (mặc dù nhiều hoạt động Counter khác yêu cầu các giá trị phải tương đương với ints).
lvc

34

Trong Python 2.7, chỉ cần làm:

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

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

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

sao chép-dán từ: http://docs.python.org/dev/l Library / collections.html #ordereddict -examples-and- recipes

Thưởng thức ;-)


25

Đây là mã:

import operator
origin_list = [
    {"name": "foo", "rank": 0, "rofl": 20000},
    {"name": "Silly", "rank": 15, "rofl": 1000},
    {"name": "Baa", "rank": 300, "rofl": 20},
    {"name": "Zoo", "rank": 10, "rofl": 200},
    {"name": "Penguin", "rank": -1, "rofl": 10000}
]
print ">> Original >>"
for foo in origin_list:
    print foo

print "\n>> Rofl sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rofl")):
    print foo

print "\n>> Rank sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rank")):
    print foo

Đây là kết quả:

Nguyên

{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}

Rofl

{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}

Cấp

{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}

25

Hãy thử cách tiếp cận sau đây. Hãy để chúng tôi xác định một từ điển được gọi là mydict với dữ liệu sau đây:

mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

Nếu một người muốn sắp xếp từ điển theo các phím, người ta có thể làm một cái gì đó như:

for key in sorted(mydict.iterkeys()):
    print "%s: %s" % (key, mydict[key])

Điều này sẽ trả về đầu ra sau:

alan: 2
bob: 1
carl: 40
danny: 3

Mặt khác, nếu một người muốn sắp xếp một từ điển theo giá trị (như được hỏi trong câu hỏi), người ta có thể làm như sau:

for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
    print "%s: %s" % (key, value)

Kết quả của lệnh này (sắp xếp từ điển theo giá trị) sẽ trả về như sau:

bob: 1
alan: 2
danny: 3
carl: 40

Tuyệt vời! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]):cho phép bạn sắp xếp theo một khóa con
Andomar

nó cho tôi lỗi cú pháp gần lambda trong Python3
Suleman Elahi

21

Bắt đầu từ Python 3.6, dictcác đối tượng hiện được sắp xếp theo thứ tự chèn. Nó chính thức nằm trong thông số kỹ thuật của Python 3.7.

>>> words = {"python": 2, "blah": 4, "alice": 3}
>>> dict(sorted(words.items(), key=lambda x: x[1]))
{'python': 2, 'alice': 3, 'blah': 4}

Trước đó, bạn phải sử dụng OrderedDict.

Tài liệu Python 3.7 nói:

Thay đổi trong phiên bản 3.7: Thứ tự từ điển được đảm bảo là thứ tự chèn. Hành vi này là chi tiết thực hiện của CPython từ 3.6.


làm việc tuyệt vời dict(sorted(words.items(), key=lambda x: x[1], reverse=True))cho DESC
vizyourdata

20

Bạn cũng có thể tạo một "chỉ mục đảo ngược"

from collections import defaultdict
inverse= defaultdict( list )
for k, v in originalDict.items():
    inverse[v].append( k )

Bây giờ nghịch đảo của bạn có các giá trị; mỗi giá trị có một danh sách các khóa áp dụng.

for k in sorted(inverse):
    print k, inverse[k]

19

Bạn có thể sử dụng các bộ sưu tập . Lưu ý, điều này sẽ làm việc cho cả giá trị số và không số.

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> from collections import Counter
>>> #To sort in reverse order
>>> Counter(x).most_common()
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> Counter(x).most_common()[::-1]
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
>>> #To get a dictionary sorted by values
>>> from collections import OrderedDict
>>> OrderedDict(Counter(x).most_common()[::-1])
OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

7
Điều này khác với câu trả lời của Ivan Sas như thế nào?
Peter Mortensen

15

Bạn có thể sử dụng bỏ qua dict là một từ điển được sắp xếp vĩnh viễn theo giá trị.

>>> data = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> SkipDict(data)
{0: 0.0, 2: 1.0, 1: 2.0, 4: 3.0, 3: 4.0}

Nếu bạn sử dụng keys(), values()hoặcitems() sau đó bạn sẽ lặp theo thứ tự được sắp xếp theo giá trị.

Nó được thực hiện bằng cách sử dụng cơ sở hạ tầng danh sách bỏ qua .


chúng ta có thể thay đổi thứ tự sắp xếp, ngay bây giờ, nó đang tăng dần, nhưng tôi muốn giảm dần.
Suleman Elahi

afaik bạn sẽ phải phủ nhận giá trị của bạn để đảo ngược thứ tự
Malthe

wow, tôi không nghĩ như vậy ... cảm ơn.
Suleman Elahi

14

Bạn cũng có thể sử dụng chức năng tùy chỉnh có thể được chuyển qua khóa.

def dict_val(x):
    return x[1]
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=dict_val)

12
from django.utils.datastructures import SortedDict

def sortedDictByKey(self,data):
    """Sorted dictionary order by key"""
    sortedDict = SortedDict()
    if data:
        if isinstance(data, dict):
            sortedKey = sorted(data.keys())
            for k in sortedKey:
                sortedDict[k] = data[k]
    return sortedDict

2
câu hỏi là: sắp xếp theo giá trị, không phải theo khóa ... Tôi thích nhìn thấy một chức năng. Bạn có thể nhập các bộ sưu tập và tất nhiên sử dụng được sắp xếp (data.values ​​())
Remi

10

Như Dilettant đã chỉ ra , Python 3.6 sẽ giữ trật tự ! Tôi nghĩ rằng tôi sẽ chia sẻ một chức năng mà tôi đã viết giúp giảm bớt việc sắp xếp một lần lặp (tuple, list, dict). Trong trường hợp sau, bạn có thể sắp xếp theo khóa hoặc giá trị và có thể tính đến so sánh số. Chỉ với> = 3,6!

Khi bạn thử sử dụng được sắp xếp trên một iterable có thể giữ ví dụ như chuỗi cũng như ints, sort () sẽ thất bại. Tất nhiên bạn có thể buộc so sánh chuỗi với str (). Tuy nhiên, trong một số trường hợp bạn muốn thực hiện so sánh số thực tế12 nhỏ hơn 20(không phải là trường hợp so sánh chuỗi). Vì vậy, tôi đã đưa ra những điều sau đây. Khi bạn muốn so sánh số rõ ràng, bạn có thể sử dụng cờ num_as_numsẽ cố gắng thực hiện sắp xếp số rõ ràng bằng cách cố gắng chuyển đổi tất cả các giá trị thành số float. Nếu thành công, nó sẽ thực hiện sắp xếp số, nếu không, nó sẽ dùng đến so sánh chuỗi.

Bình luận để cải thiện hoặc đẩy yêu cầu chào đón.

def sort_iterable(iterable, sort_on=None, reverse=False, num_as_num=False):
    def _sort(i):
      # sort by 0 = keys, 1 values, None for lists and tuples
      try:
        if num_as_num:
          if i is None:
            _sorted = sorted(iterable, key=lambda v: float(v), reverse=reverse)
          else:
            _sorted = dict(sorted(iterable.items(), key=lambda v: float(v[i]), reverse=reverse))
        else:
          raise TypeError
      except (TypeError, ValueError):
        if i is None:
          _sorted = sorted(iterable, key=lambda v: str(v), reverse=reverse)
        else:
          _sorted = dict(sorted(iterable.items(), key=lambda v: str(v[i]), reverse=reverse))

      return _sorted

    if isinstance(iterable, list):
      sorted_list = _sort(None)
      return sorted_list
    elif isinstance(iterable, tuple):
      sorted_list = tuple(_sort(None))
      return sorted_list
    elif isinstance(iterable, dict):
      if sort_on == 'keys':
        sorted_dict = _sort(0)
        return sorted_dict
      elif sort_on == 'values':
        sorted_dict = _sort(1)
        return sorted_dict
      elif sort_on is not None:
        raise ValueError(f"Unexpected value {sort_on} for sort_on. When sorting a dict, use key or values")
    else:
      raise TypeError(f"Unexpected type {type(iterable)} for iterable. Expected a list, tuple, or dict")

9

Đây là một giải pháp sử dụng zip trên d.values()d.keys() . Một vài dòng xuống liên kết này (trên các đối tượng xem từ điển) là:

Điều này cho phép tạo các cặp (giá trị, khóa) bằng cách sử dụng zip (): cặp = zip (d.values ​​(), d.keys ()).

Vì vậy, chúng ta có thể làm như sau:

d = {'key1': 874.7, 'key2': 5, 'key3': 8.1}

d_sorted = sorted(zip(d.values(), d.keys()))

print d_sorted 
# prints: [(5, 'key2'), (8.1, 'key3'), (874.7, 'key1')]

9

Tất nhiên, hãy nhớ rằng, bạn cần sử dụng OrderedDictvì từ điển Python thông thường không giữ trật tự ban đầu.

from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key=lambda x: x[1]))

Nếu bạn không có Python 2.7 trở lên, điều tốt nhất bạn có thể làm là lặp lại các giá trị trong hàm tạo. (Có một bản OrderedDict2.4 và 2.6 ở đây , nhưng

a) Tôi không biết nó hoạt động tốt như thế nào

b) Bạn phải tải xuống và cài đặt nó tất nhiên. Nếu bạn không có quyền truy cập quản trị, thì tôi sợ tùy chọn này bị loại.)


def gen(originalDict):
    for x, y in sorted(zip(originalDict.keys(), originalDict.values()), key=lambda z: z[1]):
        yield (x, y)
    #Yields as a tuple with (key, value). You can iterate with conditional clauses to get what you want. 

for bleh, meh in gen(myDict):
    if bleh == "foo":
        print(myDict[bleh])

Bạn cũng có thể in ra mọi giá trị

for bleh, meh in gen(myDict):
    print(bleh, meh)

Hãy nhớ xóa dấu ngoặc đơn sau khi in nếu không sử dụng Python 3.0 trở lên


từ điển Python thông thường không giữ thứ tự ban đầu - kể từ Python 3.7, chúng có.
gerrit

7

Sử dụng ValueSortDict từ dicts :

from dicts.sorteddict import ValueSortedDict
d = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_dict = ValueSortedDict(d)
print sorted_dict.items() 

[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

6

Điều này hoạt động trong 3.1.x:

import operator
slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
print(slovar_sorted)

6

Chỉ cần học kỹ năng liên quan từ Python cho mọi người .

Bạn có thể sử dụng danh sách tạm thời để giúp bạn sắp xếp từ điển:

#Assume dictionary to be:
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}

# create a temporary list
tmp = []

# iterate through the dictionary and append each tuple into the temporary list 
for key, value in d.items():
    tmptuple = (value, key)
    tmp.append(tmptuple)

# sort the list in ascending order
tmp = sorted(tmp)

print (tmp)

Nếu bạn muốn sắp xếp danh sách theo thứ tự giảm dần, chỉ cần thay đổi dòng sắp xếp ban đầu thành:

tmp = sorted(tmp, reverse=True)

Sử dụng khả năng hiểu danh sách, một lớp lót sẽ là:

#Assuming the dictionary looks like
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
#One liner for sorting in ascending order
print (sorted([(v, k) for k, v in d.items()]))
#One liner for sorting in descending order
print (sorted([(v, k) for k, v in d.items()], reverse=True))

Đầu ra mẫu:

#Asending order
[(1.0, 'orange'), (500.1, 'apple'), (789.0, 'pineapple'), (1500.2, 'banana')]
#Descending order
[(1500.2, 'banana'), (789.0, 'pineapple'), (500.1, 'apple'), (1.0, 'orange')]

đây là sắp xếp theo khóa, không phải theo giá trị.
Rubel

Nếu bạn muốn in nó ở định dạng ban đầu, bạn nên làm: print ([(k, v) cho v, k theo thứ tự ([(v, k) cho k, v trong d.items ()])]). Đầu ra là: [('cam', 1.0), ('apple', 500.1), ('dứa', 789.0), ('chuối', 1500.2)]. Với [(k, v) cho v, k được sắp xếp ([(v, k) cho k, v trong d.items ()], Reverse = True)] đầu ra là: [('Banana', 1500.2), ('Dứa', 789.0), ('táo', 500.1), ('cam', 1.0)]
Hermes Morales

5

Lặp lại thông qua một lệnh và sắp xếp nó theo các giá trị của nó theo thứ tự giảm dần:

$ python --version
Python 3.2.2

$ cat sort_dict_by_val_desc.py 
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for word in sorted(dictionary, key=dictionary.get, reverse=True):
  print(word, dictionary[word])

$ python sort_dict_by_val_desc.py 
aina 5
tuli 4
joka 3
sana 2
siis 1

5

Nếu giá trị của bạn là số nguyên và bạn sử dụng Python 2.7 trở lên, bạn có thể sử dụng collections.Counterthay vì dict. Các most_commonphương pháp sẽ cung cấp cho bạn tất cả các mục, sắp xếp theo giá trị.


5

Để hoàn thiện, tôi đăng một giải pháp bằng cách sử dụng heapq . Lưu ý, phương pháp này sẽ hoạt động cho cả giá trị số và không số

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> x_items = x.items()
>>> heapq.heapify(x_items)
>>> #To sort in reverse order
>>> heapq.nlargest(len(x_items),x_items, operator.itemgetter(1))
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> heapq.nsmallest(len(x_items),x_items, operator.itemgetter(1))
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

4

Do các yêu cầu để duy trì khả năng tương thích ngược với các phiên bản cũ hơn của Python tôi nghĩ rằng giải pháp OrderedDict rất không khôn ngoan. Bạn muốn một cái gì đó hoạt động với Python 2.7 và các phiên bản cũ hơn.

Nhưng giải pháp bộ sưu tập được đề cập trong một câu trả lời khác là hoàn toàn tuyệt vời, bởi vì bạn giữ lại một kết nối giữa khóa và giá trị mà trong trường hợp từ điển là vô cùng quan trọng.

Tôi không đồng ý với lựa chọn số một được đưa ra trong một câu trả lời khác, vì nó vứt bỏ chìa khóa.

Tôi đã sử dụng giải pháp được đề cập ở trên (mã hiển thị bên dưới) và giữ quyền truy cập vào cả khóa và giá trị và trong trường hợp của tôi, thứ tự là trên các giá trị, nhưng điều quan trọng là thứ tự của các khóa sau khi sắp xếp các giá trị.

from collections import Counter

x = {'hello':1, 'python':5, 'world':3}
c=Counter(x)
print c.most_common()


>> [('python', 5), ('world', 3), ('hello', 1)]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.