Làm thế nào tôi có thể sắp xếp một từ điển theo khóa?


940

Điều gì sẽ là một cách tốt đẹp để đi từ {2:3, 1:89, 4:5, 3:0}đến {1:89, 2:3, 3:0, 4:5}?
Tôi đã kiểm tra một số bài viết nhưng tất cả đều sử dụng toán tử "được sắp xếp" trả về các bộ dữ liệu.


39
Từ điển về bản chất là không phân loại. Hiển thị từ điển là một vấn đề khác. Dù sao, bạn thực sự cần phải sắp xếp nó để làm gì?
Karl Knechtel

15
từ điển không được sắp xếp. họ chỉ không có. nếu bạn muốn xem qua các yếu tố theo thứ tự, bạn phải làm điều gì đó như bạn đã nói bằng cách sử dụng sắp xếp như "for key in sort (d.keys ())" giả sử d là tên của từ điển của bạn
Ryan Hained

3
@KarlKnechtel - trường hợp sử dụng của tôi là tôi có ứng dụng CLI có menu nguyên thủy và các tùy chọn menu nằm trong từ điển làm khóa. Tôi muốn hiển thị các phím theo thứ tự abc cho sự tỉnh táo của người dùng.
Randy


4
Lưu ý rằng các ký tự hiện được sắp xếp theo thứ tự chèn (python 3.6+). Một số câu trả lời dưới đây chỉ ra điều này.
matiasg

Câu trả lời:


940

Từ điển Python chuẩn không có thứ tự. Ngay cả khi bạn đã sắp xếp các cặp (khóa, giá trị), bạn sẽ không thể lưu trữ chúng dicttheo cách bảo toàn thứ tự.

Cách dễ nhất là sử dụng OrderedDict, ghi nhớ thứ tự các phần tử đã được chèn:

In [1]: import collections

In [2]: d = {2:3, 1:89, 4:5, 3:0}

In [3]: od = collections.OrderedDict(sorted(d.items()))

In [4]: od
Out[4]: OrderedDict([(1, 89), (2, 3), (3, 0), (4, 5)])

Đừng bận tâm đến cách odđược in ra; nó sẽ hoạt động như mong đợi:

In [11]: od[1]
Out[11]: 89

In [12]: od[3]
Out[12]: 0

In [13]: for k, v in od.iteritems(): print k, v
   ....: 
1 89
2 3
3 0
4 5

Con trăn 3

Đối với người dùng Python 3, người ta cần sử dụng .items()thay vì .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5

1
Tôi đã sử dụng cái này và nó hoạt động, tôi đoán thêm mã và dự phòng của nó nhưng hoàn thành công việc, # unordered dict d = {2: 3, 1:89, 4: 5, 3: 0} orderDict = {} cho khóa được sắp xếp (d.iterkeys ()): orderDict [key] = d [key]
Antony

4
@achrysochoou: nếu nó hoạt động, chắc chắn là do may mắn. Như bạn đã nói, từ điển thông thường không có khái niệm sắp xếp, bất kể bạn gán các khóa được sắp xếp hay theo cách ngẫu nhiên.
Ricardo Cárdenes

21
Đối với trăn 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618

10
python 3.7+ không cần orderDict vì hiện tại nó đặt hàng theo mặc định :-)
Aneuway

3
Từ hướng dẫn sử dụng python 3.7.4: "Danh sách thực hiện (d) trên từ điển trả về danh sách tất cả các khóa được sử dụng trong từ điển, theo thứ tự chèn". Vì vậy, thứ tự chèn là một cái gì đó được bảo tồn và chúng ta có thể dựa vào.
Mostafa Hadian

415

Bản thân từ điển không có thứ tự như vậy, nếu bạn muốn in chúng vv theo một số thứ tự, đây là một số ví dụ:

Trong Python 2.4 trở lên:

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

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

cho:

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

(Python dưới 2.4 :)

keylist = mydict.keys()
keylist.sort()
for key in keylist:
    print "%s: %s" % (key, mydict[key])

Nguồn: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dipedia-by-keys/


2
Bạn cũng có thể sử dụng OrderedDict trong python 2.4+ như trong câu trả lời của NPE
radtek

1
và nếu bạn đang sử dụng vật phẩm (), bạn có thể làm như thếfor key, value in sorted(mydict.items())"
beep_check

Bản thân từ điển không có thứ tự như vậy -> không còn đúng nữa!
minexew

Làm thế nào đến, bạn có thể giải thích?
James

204

Từ tài liệu thư viện của Pythoncollections :

>>> from collections import OrderedDict

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

>>> # dictionary sorted by key -- OrderedDict(sorted(d.items()) also works
>>> 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)])

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

4
tuyệt vời! Guys nếu bạn muốn đảo ngược thứ tự (tăng dần thành giảm dần) sau đó bạn chỉ cần thêm reverse=Trueví dụOrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
benscabbia

1
Trong PyCharm, bất kể tôi sử dụng từ điển nào, tôi luôn nhận được cảnh báo này:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter

153

Đối với CPython / PyPy 3.6 và bất kỳ Python 3.7 nào trở lên, việc này được thực hiện dễ dàng với:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}

3
Một cách khác để viết điều tương tự là sử dụng cách hiểu: {key:d[key] for key in sorted(d.keys())}
Flow2k

41

Có một số mô-đun Python cung cấp các cài đặt từ điển tự động duy trì các khóa theo thứ tự được sắp xếp. Hãy xem xét mô-đun sortcontainers là các triển khai Python thuần túy và nhanh như C. Ngoài ra còn có một so sánh hiệu suất với các tùy chọn phổ biến khác được điểm chuẩn so với nhau.

Sử dụng một lệnh chính tả là một giải pháp không đầy đủ nếu bạn cần liên tục thêm và xóa các cặp khóa / giá trị trong khi lặp lại.

>>> from sortedcontainers import SortedDict
>>> d = {2:3, 1:89, 4:5, 3:0}
>>> s = SortedDict(d)
>>> s.items()
[(1, 89), (2, 3), (3, 0), (4, 5)]

Loại SortedDict cũng hỗ trợ tra cứu và xóa vị trí được lập chỉ mục không thể thực hiện được với loại chính tả tích hợp.

>>> s.iloc[-1]
4
>>> del s.iloc[2]
>>> s.keys()
SortedSet([1, 2, 4])

32

Đơn giản:

d = {2:3, 1:89, 4:5, 3:0}
sd = sorted(d.items())

for k,v in sd:
    print k, v

Đầu ra:

1 89
2 3
3 0
4 5

6
sdlà một danh sách các bộ dữ liệu, không phải là một từ điển. (mặc dù vẫn hữu ích.)
nischi

24

Như những người khác đã đề cập, từ điển vốn đã không có thứ tự. Tuy nhiên, nếu vấn đề chỉ đơn thuần là hiển thị từ điển theo kiểu có thứ tự, bạn có thể ghi đè __str__phương thức trong lớp con từ điển và sử dụng lớp từ điển này thay vì dựng sẵn dict. Ví dụ.

class SortedDisplayDict(dict):
   def __str__(self):
       return "{" + ", ".join("%r: %r" % (key, self[key]) for key in sorted(self)) + "}"


>>> d = SortedDisplayDict({2:3, 1:89, 4:5, 3:0})
>>> d
{1: 89, 2: 3, 3: 0, 4: 5}

Lưu ý, điều này không thay đổi gì về cách các khóa được lưu trữ, thứ tự chúng sẽ quay trở lại khi bạn lặp lại chúng, v.v., chỉ cách chúng được hiển thị cùng printhoặc tại bảng điều khiển python.


19

Tìm thấy một cách khác:

import json
print json.dumps(d, sort_keys = True)

upd:
1. cái này cũng sắp xếp các đối tượng lồng nhau (cảm ơn @DanielF).
2. từ điển python không được sắp xếp theo thứ tự do đó chỉ có thể in hoặc gán cho str.


Nhưng điều này cũng sắp xếp các khóa của các đối tượng lồng nhau, có thể không muốn.
Daniel F

Lưu ý rằng điều này chỉ sắp xếp từ điển, không phải danh sách, ví dụ dict.keys () sẽ không được sắp xếp vì đây là danh sách.
Andrew

16

Trong Python 3.

>>> D1 = {2:3, 1:89, 4:5, 3:0}
>>> for key in sorted(D1):
    print (key, D1[key])

cho

1 89
2 3
3 0
4 5

13

Từ điển Python đã được sắp xếp trước Python 3.6. Trong triển khai CPython của Python 3.6, từ điển sẽ giữ thứ tự chèn. Từ Python 3.7, đây sẽ trở thành một tính năng ngôn ngữ.

Trong danh sách của Python 3.6 ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

Khía cạnh giữ trật tự của triển khai mới này được coi là một chi tiết triển khai và không nên dựa vào (điều này có thể thay đổi trong tương lai, nhưng mong muốn có triển khai chính tả mới này trong 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, điều này cũng 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).

Trong tài liệu của Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries ):

Danh sách thực hiện (d) trên một từ điển trả về một danh sách tất cả các khóa được sử dụng trong từ điển, theo thứ tự chèn (nếu bạn muốn nó được sắp xếp, thay vào đó chỉ sử dụng được sắp xếp (d)).

Vì vậy, không giống như các phiên bản trước, bạn có thể sắp xếp một lệnh sau Python 3.6 / 3.7. Nếu bạn muốn sắp xếp một dict lồng nhau bao gồm cả dict phụ bên trong, bạn có thể làm:

test_dict = {'a': 1, 'c': 3, 'b': {'b2': 2, 'b1': 1}}

def dict_reorder(item):
    return {k: sort_dict(v) if isinstance(v, dict) else v for k, v in sorted(item.items())}

reordered_dict = dict_reorder(test_dict)

https://gist.github.com/ligyxy/f60f0374defc383aa098d44cfbd318eb


11

Ở đây tôi tìm thấy một số giải pháp đơn giản nhất để sắp xếp dict python bằng phím sử dụng pprint. ví dụ.

>>> x = {'a': 10, 'cd': 20, 'b': 30, 'az': 99} 
>>> print x
{'a': 10, 'b': 30, 'az': 99, 'cd': 20}

nhưng trong khi sử dụng pprint, nó sẽ trả về dict được sắp xếp

>>> import pprint 
>>> pprint.pprint(x)
{'a': 10, 'az': 99, 'b': 30, 'cd': 20}

10

Có một cách dễ dàng để sắp xếp một từ điển.

Theo câu hỏi của bạn,

Giải pháp là :

c={2:3, 1:89, 4:5, 3:0}
y=sorted(c.items())
print y

(Trong đó c, là tên của từ điển của bạn.)

Chương trình này cung cấp đầu ra sau:

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

như bạn muốn

Một ví dụ khác là:

d={"John":36,"Lucy":24,"Albert":32,"Peter":18,"Bill":41}
x=sorted(d.keys())
print x

Cung cấp đầu ra:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

y=sorted(d.values())
print y

Cung cấp đầu ra:[18, 24, 32, 36, 41]

z=sorted(d.items())
print z

Cung cấp đầu ra:

[('Albert', 32), ('Bill', 41), ('John', 36), ('Lucy', 24), ('Peter', 18)]

Do đó bằng cách thay đổi nó thành khóa, giá trị và vật phẩm, bạn có thể in như những gì bạn muốn. Hy vọng điều này sẽ giúp!


8

Sẽ tạo ra chính xác những gì bạn muốn:

 D1 = {2:3, 1:89, 4:5, 3:0}

 sort_dic = {}

 for i in sorted(D1):
     sort_dic.update({i:D1[i]})
 print sort_dic


{1: 89, 2: 3, 3: 0, 4: 5}

Nhưng đây không phải là cách chính xác để làm điều này, bởi vì, Nó có thể hiển thị một hành vi khác biệt với các từ điển khác nhau, mà tôi đã học gần đây. Do đó, cách hoàn hảo đã được Tim đề xuất Trong phản hồi Truy vấn của tôi mà tôi đang chia sẻ ở đây.

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))

"Hiển thị một hành vi khác biệt với các từ điển khác nhau" có nghĩa là gì? "Hành vi khác biệt" được sắp xếp không thể xử lý là gì?
ingyhere

6

Tôi nghĩ cách dễ nhất là sắp xếp dict theo khóa và lưu cặp khóa: value được sắp xếp trong một dict mới.

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be neccessary
        dict2[key] = dict1[key]

Để làm cho nó rõ ràng hơn:

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted     values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be  neccessary
        value = dict1[key]
        dict2[key] = value

6

Bạn có thể tạo một từ điển mới bằng cách sắp xếp từ điển hiện tại theo khóa theo câu hỏi của bạn.

Đây là từ điển của bạn

d = {2:3, 1:89, 4:5, 3:0}

Tạo một từ điển mới d1 bằng cách sắp xếp d này bằng hàm lambda

d1 = dict(sorted(d.items(), key = lambda x:x[0]))

d1 phải là {1: 89, 2: 3, 3: 0, 4: 5}, được sắp xếp dựa trên các khóa trong d.


5

Python dicts là không theo thứ tự. Thông thường, đây không phải là vấn đề vì trường hợp sử dụng phổ biến nhất là thực hiện tra cứu.

Cách đơn giản nhất để làm những gì bạn muốn là tạo một collections.OrderedDictphần tử chèn theo thứ tự được sắp xếp.

ordered_dict = collections.OrderedDict([(k, d[k]) for k in sorted(d.keys())])

Nếu bạn cần lặp lại, như những người khác ở trên đã đề xuất, cách đơn giản nhất là lặp lại các khóa được sắp xếp. Ví dụ-

In các giá trị được sắp xếp theo các phím:

# create the dict
d = {k1:v1, k2:v2,...}
# iterate by keys in sorted order
for k in sorted(d.keys()):
    value = d[k]
    # do something with k, value like print
    print k, value

Nhận danh sách các giá trị được sắp xếp theo các khóa:

values = [d[k] for k in sorted(d.keys())]

2
for k,value in sorted(d.items()):là tốt hơn: tránh truy cập dict bằng khóa một lần nữa trong vòng lặp
Jean-François Fabre

4

Tôi đến với phân loại dict dòng duy nhất.

>> a = {2:3, 1:89, 4:5, 3:0}
>> c = {i:a[i] for i in sorted(a.keys())}
>> print(c)
{1: 89, 2: 3, 3: 0, 4: 5}
[Finished in 0.4s]

Hy vọng điều này sẽ hữu ích.


4

Hàm này sẽ sắp xếp bất kỳ từ điển đệ quy theo khóa của nó. Đó là, nếu bất kỳ giá trị nào trong từ điển cũng là một từ điển, thì nó cũng sẽ được sắp xếp theo khóa của nó. Nếu bạn đang chạy trên CPython 3.6 trở lên, thay đổi đơn giản để sử dụng dictthay vì OrderedDictcó thể được thực hiện.

from collections import OrderedDict

def sort_dict(d):
    items = [[k, v] for k, v in sorted(d.items(), key=lambda x: x[0])]
    for item in items:
        if isinstance(item[1], dict):
            item[1] = sort_dict(item[1])
    return OrderedDict(items)
    #return dict(items)

2

Các bạn đang làm mọi thứ trở nên phức tạp ... nó thực sự đơn giản

from pprint import pprint
Dict={'B':1,'A':2,'C':3}
pprint(Dict)

Đầu ra là:

{'A':2,'B':1,'C':3}

Được nâng cấp bởi vì tôi không biết từ điển sắp xếp dấu vân tay để hiển thị chúng, nhưng OP thực sự đã hỏi về việc "đi" từ chưa được sắp xếp sang đọc chính tả, tức là OP dường như muốn một cái gì đó vẫn được sắp xếp trong bộ nhớ, có lẽ đối với một số thuật toán yêu cầu các khóa được sắp xếp
Thuyền trưởng Lepton

Phương pháp này sẽ không cho phép gán chuỗi vì pprint không trả về. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = pprint (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () TracBack (cuộc gọi gần đây nhất): Tệp "<stdin>", dòng 1, trong <module> AttributionError: đối tượng 'noneType' không có thuộc tính 'loại'

2

Giải pháp đơn giản nhất là bạn sẽ nhận được một danh sách khóa dict được sắp xếp theo thứ tự và sau đó lặp qua dict. Ví dụ

a1 = {'a':1, 'b':13, 'd':4, 'c':2, 'e':30}
a1_sorted_keys = sorted(a1, key=a1.get, reverse=True)
for r in a1_sorted_keys:
    print r, a1[r]

Sau đây sẽ là đầu ra (thứ tự chờ)

e 30
b 13
d 4
c 2
a 1

2

Một cách dễ dàng để làm điều này:

d = {2:3, 1:89, 4:5, 3:0}

s = {k : d[k] for k in sorted(d)}

s
Out[1]: {1: 89, 2: 3, 3: 0, 4: 5} 

1

So sánh thời gian của hai phương thức trong 2.7 cho thấy chúng gần như giống hệt nhau:

>>> setup_string = "a = sorted(dict({2:3, 1:89, 4:5, 3:0}).items())"
>>> timeit.timeit(stmt="[(k, val) for k, val in a]", setup=setup_string, number=10000)
0.003599141953657181

>>> setup_string = "from collections import OrderedDict\n"
>>> setup_string += "a = OrderedDict({1:89, 2:3, 3:0, 4:5})\n"
>>> setup_string += "b = a.items()"
>>> timeit.timeit(stmt="[(k, val) for k, val in b]", setup=setup_string, number=10000)
0.003581275490432745 

1
from operator import itemgetter
# if you would like to play with multiple dictionaries then here you go:
# Three dictionaries that are composed of first name and last name.
user = [
    {'fname': 'Mo', 'lname': 'Mahjoub'},
    {'fname': 'Abdo', 'lname': 'Al-hebashi'},
    {'fname': 'Ali', 'lname': 'Muhammad'}
]
#  This loop will sort by the first and the last names.
# notice that in a dictionary order doesn't matter. So it could put the first name first or the last name first. 
for k in sorted (user, key=itemgetter ('fname', 'lname')):
    print (k)

# This one will sort by the first name only.
for x in sorted (user, key=itemgetter ('fname')):
    print (x)

1
dictionary = {1:[2],2:[],5:[4,5],4:[5],3:[1]}

temp=sorted(dictionary)
sorted_dict = dict([(k,dictionary[k]) for i,k in enumerate(temp)])

sorted_dict:
         {1: [2], 2: [], 3: [1], 4: [5], 5: [4, 5]}


0

Đề nghị của tôi là điều này vì nó cho phép bạn sắp xếp một dict hoặc giữ một dict được sắp xếp khi bạn đang thêm các mục và có thể cần thêm các mục trong tương lai:

Xây dựng dicttừ đầu khi bạn đi cùng. Có cấu trúc dữ liệu thứ hai, một danh sách, với danh sách các khóa của bạn. Gói bisect có chức năng insort cho phép chèn vào danh sách được sắp xếp hoặc sắp xếp danh sách của bạn sau khi điền hoàn toàn lệnh của bạn. Bây giờ, khi bạn lặp lại lệnh chính của mình, thay vào đó bạn lặp lại danh sách để truy cập từng khóa theo thứ tự mà không lo lắng về việc biểu diễn cấu trúc chính tả (không được tạo ra để sắp xếp).


-1
l = dict.keys()
l2 = l
l2.append(0)
l3 = []
for repeater in range(0, len(l)):
    smallnum = float("inf")
    for listitem in l2:
        if listitem < smallnum:
            smallnum = listitem
    l2.remove(smallnum)
    l3.append(smallnum)
l3.remove(0)
l = l3

for listitem in l:
    print(listitem)

3
Có 14 câu trả lời khác. Bạn có thể giải thích mã của bạn một chút và tại sao nó có thể tốt hơn các giải pháp khác không?
FelixSFD

Downvote - Mã khá khó đọc với các tên biến vô nghĩa ngắn l, l2, l3. Có vẻ là một nỗ lực ở một thuật toán gián tiếp và không hiệu quả, không có kiến ​​thức về các hàm tiêu chuẩn python, và trong mọi trường hợp không hoạt động khi được thử nghiệm trên ví dụ nhỏ trong bài gốc.
Thuyền trưởng Lepton
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.