Bagaimana saya bisa mengurutkan kamus berdasarkan kunci?

941

Apa yang akan menjadi cara yang bagus untuk pergi dari {2:3, 1:89, 4:5, 3:0}ke {1:89, 2:3, 3:0, 4:5}?
Saya memeriksa beberapa posting tetapi mereka semua menggunakan operator "diurutkan" yang mengembalikan tupel.

Antony
sumber
39
Kamus pada dasarnya tidak disortir. Menampilkan kamus adalah masalah lain. Ngomong-ngomong, untuk apa kamu benar-benar memilahnya?
Karl Knechtel
15
kamus tidak diurutkan. mereka hanya arent. jika Anda ingin menelusuri elemen-elemen agar Anda harus melakukan sesuatu seperti yang Anda katakan menggunakan diurutkan seperti "untuk kunci diurutkan (d.keys ())" dengan asumsi d adalah nama kamus Anda
Ryan Haining
3
@KarlKnechtel - use case saya adalah saya memiliki aplikasi CLI yang memiliki menu primitif dan opsi menu ada di kamus sebagai kuncinya. Saya ingin menampilkan tombol-tombol sesuai abjad untuk kewarasan pengguna.
Randy
4
Perhatikan bahwa dikt sekarang dipesan dengan urutan penyisipan (python 3.6+). Beberapa jawaban di bawah menunjukkan hal ini.
matiasg

Jawaban:

941

Kamus Python standar tidak berurutan. Bahkan jika Anda mengurutkan pasangan (kunci, nilai), Anda tidak akan dapat menyimpannya dictdengan cara yang akan mempertahankan pemesanan.

Cara termudah adalah menggunakan OrderedDict, yang mengingat urutan elemen-elemen yang telah dimasukkan:

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

Tidak masalah cara oddicetak; itu akan bekerja seperti yang diharapkan:

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

Python 3

Untuk pengguna Python 3, orang perlu menggunakan .items()alih - alih .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5
NPE
sumber
1
Saya menggunakan ini dan berfungsi, saya kira lebih banyak kode dan redundansi tetapi menyelesaikan pekerjaan, # unordered dict d = {2: 3, 1:89, 4: 5, 3: 0} orderedDict = {} untuk kunci yang diurutkan (d.iterkeys ()): orderedDict [key] = d [key]
Antony
4
@achrysochoou: jika itu berhasil, itu pasti karena keberuntungan belaka. Seperti yang telah diberitahukan kepada Anda, kamus reguler tidak memiliki konsep pengurutan, tidak masalah jika Anda menetapkan kunci diurutkan atau secara acak.
Ricardo Cárdenes
21
Untuk python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618
10
python 3.7+ seharusnya tidak perlu dipesanDict karena sekarang memesan secara default :-)
Aneuway
3
Dari manual python 3.7.4: "Daftar berkinerja (d) pada kamus mengembalikan daftar semua kunci yang digunakan dalam kamus, dalam urutan penyisipan". Jadi urutan penyisipan adalah sesuatu yang dilestarikan dan bisa kita andalkan.
Mostafa Hadian
415

Kamus sendiri tidak memiliki barang pesanan seperti itu, jika Anda ingin mencetaknya dll untuk beberapa pesanan, berikut adalah beberapa contoh:

Dalam Python 2.4 dan di atasnya:

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

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

memberi:

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

(Python di bawah 2.4 :)

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

Sumber: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dictionary-by-keys/

James
sumber
2
Anda juga dapat menggunakan OrderedDict dengan python 2.4+ seperti pada jawaban NPE
radtek
1
dan jika Anda menggunakan item () Anda dapat melakukannya sepertifor key, value in sorted(mydict.items())"
beep_check
Kamus sendiri tidak memiliki barang pesanan seperti itu -> tidak lagi benar!
minexew
Kenapa bisa Anda jelaskan?
James
204

Dari dokumentasi perpustakaan 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)])
Dennis
sumber
4
luar biasa! Guys jika Anda ingin membalik urutan (naik ke turun) maka Anda cukup menambahkan reverse=TruemisalnyaOrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
benscabbia
1
Di PyCharm, apa pun kamus yang saya gunakan, saya selalu mendapatkan peringatan ini:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter
153

Untuk CPython / PyPy 3.6, dan Python 3.7 atau lebih tinggi, ini mudah dilakukan dengan:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}
Dipu
sumber
3
Cara lain untuk menulis hal yang sama adalah menggunakan pemahaman: {key:d[key] for key in sorted(d.keys())}
flow2k
41

Ada sejumlah modul Python yang menyediakan implementasi kamus yang secara otomatis menjaga kunci dalam urutan diurutkan. Pertimbangkan modul yang diurutkan yang merupakan implementasi pure-Python dan fast-as-C. Ada juga perbandingan kinerja dengan opsi populer lainnya yang dibandingkan satu sama lain.

Menggunakan perintah dict adalah solusi yang tidak memadai jika Anda perlu terus-menerus menambah dan menghapus pasangan kunci / nilai sambil juga mengulangi.

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

Tipe SortedDict juga mendukung pencarian dan penghapusan lokasi yang diindeks yang tidak mungkin dilakukan dengan tipe dikt bawaan.

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

Secara sederhana:

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

for k,v in sd:
    print k, v

Keluaran:

1 89
2 3
3 0
4 5
pengguna3769249
sumber
6
sdadalah daftar tupel, bukan kamus. (masih berguna.)
nischi
24

Seperti yang disebutkan orang lain, kamus pada dasarnya tidak berurutan. Namun, jika masalah ini hanya menampilkan kamus dengan cara yang teratur, Anda dapat mengganti __str__metode dalam subkelas kamus, dan menggunakan kelas kamus ini daripada builtin dict. Misalnya.

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}

Catatan, ini tidak mengubah apa pun tentang bagaimana kunci disimpan, urutan mereka akan kembali ketika Anda mengulanginya dll, hanya bagaimana mereka ditampilkan dengan printatau di konsol python.

Brian
sumber
19

Menemukan cara lain:

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

upd:
1. ini juga mengurutkan objek bersarang (terima kasih @DanielF).
2. kamus python tidak terurut sehingga ini dapat dijahitkan untuk dicetak atau ditugaskan ke str saja.

tschesseket
sumber
Tapi ini juga memilah kunci objek bersarang, yang mungkin tidak diinginkan.
Daniel F
Perhatikan bahwa ini hanya mengurutkan kamus, bukan daftar, mis. Dict.keys () tidak akan disortir karena ini adalah daftar.
Andrew
16

Dalam Python 3.

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

memberi

1 89
2 3
3 0
4 5
Evgeny Tryastsin
sumber
13

Kamus Python tidak berurutan sebelum Python 3.6. Dalam implementasi CPython dari Python 3.6, kamus menjaga urutan penyisipan. Dari Python 3.7, ini akan menjadi fitur bahasa.

Di changelog dari Python 3.6 ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

Aspek pelestarian pesanan dari implementasi baru ini dianggap sebagai detail implementasi dan tidak boleh diandalkan (ini dapat berubah di masa depan, tetapi diharapkan memiliki implementasi dict baru ini dalam bahasa untuk beberapa rilis sebelum mengubah spesifikasi bahasa untuk mengamanatkan semantik pengawet pesanan untuk semua implementasi Python saat ini dan di masa depan, ini juga membantu menjaga kompatibilitas ke belakang dengan versi bahasa yang lebih lama di mana urutan iterasi acak masih berlaku, misalnya Python 3.5).

Dalam dokumen Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries ):

Melakukan daftar (d) pada kamus mengembalikan daftar semua kunci yang digunakan dalam kamus, dalam urutan penyisipan (jika Anda ingin diurutkan, gunakan saja diurutkan (d) sebagai gantinya).

Jadi tidak seperti versi sebelumnya, Anda dapat mengurutkan dict setelah Python 3.6 / 3.7. Jika Anda ingin menyortir dict bersarang termasuk sub-di dalam, Anda dapat melakukan:

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

Guangyang Li
sumber
11

Di sini saya menemukan beberapa solusi paling sederhana untuk mengurutkan python dict dengan menggunakan kunci pprint. misalnya.

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

tetapi saat menggunakan pprint itu akan mengembalikan dict dict

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

Ada cara mudah untuk mengurutkan kamus.

Sesuai dengan pertanyaan Anda,

Solusinya adalah:

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

(Di mana c, adalah nama kamus Anda.)

Program ini memberikan output sebagai berikut:

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

seperti yang kamu inginkan.

Contoh lain adalah:

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

Memberikan output:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

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

Memberikan output:[18, 24, 32, 36, 41]

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

Memberikan output:

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

Oleh karena itu dengan mengubahnya menjadi kunci, nilai, dan item, Anda dapat mencetak seperti apa yang Anda inginkan. Semoga ini bisa membantu!

Sree
sumber
8

Akan menghasilkan apa yang Anda inginkan:

 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}

Tapi ini bukan cara yang tepat untuk melakukan ini, karena, itu bisa menunjukkan perilaku yang berbeda dengan kamus yang berbeda, yang telah saya pelajari baru-baru ini. Oleh karena itu cara yang sempurna telah disarankan oleh Tim Dalam tanggapan atas Pertanyaan saya yang saya bagikan di sini.

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))
Jax
sumber
Apa yang dimaksud "menunjukkan perilaku berbeda dengan kamus berbeda"? Apa "perilaku berbeda" yang diurutkan tidak bisa ditangani?
ingyhere
6

Saya pikir hal yang paling mudah adalah dengan mengurutkan dict dengan kunci dan menyimpan kunci yang diurutkan: pasangan nilai dalam dict baru.

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]

Untuk membuatnya lebih jelas:

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
lallolu
sumber
6

Anda dapat membuat kamus baru dengan mengurutkan kamus saat ini berdasarkan kunci sesuai pertanyaan Anda.

Ini kamus Anda

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

Buat kamus baru d1 dengan mengurutkan ini d menggunakan fungsi lambda

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

d1 harus {1: 89, 2: 3, 3: 0, 4: 5}, diurutkan berdasarkan kunci dalam d.

Amit Prafulla
sumber
5

Dicts python tidak dipesan. Biasanya, ini bukan masalah karena use case yang paling umum adalah melakukan pencarian.

Cara paling sederhana untuk melakukan apa yang Anda inginkan adalah dengan membuat collections.OrderedDictelemen yang dimasukkan dalam urutan terurut.

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

Jika Anda perlu mengulangi, seperti yang disarankan orang lain di atas, cara paling sederhana adalah dengan mengulangi kunci yang diurutkan. Contoh-

Nilai cetak diurutkan berdasarkan kunci:

# 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

Dapatkan daftar nilai yang diurutkan berdasarkan kunci:

values = [d[k] for k in sorted(d.keys())]
Ramashish Baranwal
sumber
2
for k,value in sorted(d.items()):lebih baik: menghindari mengakses dict dengan kunci lagi di loop
Jean-François Fabre
4

Saya datang dengan menyortir baris tunggal.

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

Semoga ini bisa membantu.

Jeevan Chaitanya
sumber
4

Fungsi ini akan mengurutkan kamus apa pun secara rekursif berdasarkan kuncinya. Artinya, jika nilai apa pun dalam kamus juga merupakan kamus, nilai itu juga akan diurutkan berdasarkan kuncinya. Jika Anda menjalankan CPython 3.6 atau lebih besar, daripada perubahan sederhana untuk menggunakan dictdaripada OrderedDictdapat dibuat.

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)
Booboo
sumber
2

Kalian membuat hal-hal rumit ... itu sangat sederhana

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

Outputnya adalah:

{'A':2,'B':1,'C':3}
Derick Fdo
sumber
Dipilih karena saya tidak tahu kamus jenis cetakan untuk menampilkannya, tetapi OP telah benar-benar bertanya tentang "beralih" dari dict yang tidak disortir ke yang diurutkan, yaitu OP tampaknya menginginkan sesuatu yang tetap diurutkan dalam memori, mungkin untuk beberapa algoritma yang memerlukan kunci yang diurutkan.
Kapten Lepton
Metode ini tidak akan mengizinkan penugasan berantai karena print tidak mengembalikan apa pun. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = print (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () Traceback (panggilan terakhir terakhir): File "<stdin>", baris 1, dalam <module> AttributeError: objek 'NoneType' tidak memiliki atribut 'type'
2

Solusi paling sederhana adalah Anda harus mendapatkan daftar kunci dict diurutkan urutan dan kemudian beralih lebih dari dict. Sebagai contoh

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]

Berikut ini akan menjadi output (desending order)

e 30
b 13
d 4
c 2
a 1
Syafiq
sumber
2

Cara mudah untuk melakukan ini:

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} 
pr94
sumber
1

Perbandingan waktu dari kedua metode di 2.7 menunjukkan mereka hampir identik:

>>> 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 
Jesuisme
sumber
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)
Mohammad Mahjoub
sumber
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]}
Mahdi Ghelichi
sumber
1

Atau gunakan pandas,

Demo:

>>> d={'B':1,'A':2,'C':3}
>>> df=pd.DataFrame(d,index=[0]).sort_index(axis=1)
   A  B  C
0  2  1  3
>>> df.to_dict('int')[0]
{'A': 2, 'B': 1, 'C': 3}
>>> 

Lihat:

Dokumen ini

Dokumentasi seluruh panda

U10-Maju
sumber
0

Saran saya adalah ini karena memungkinkan Anda untuk mengurutkan dict atau menyimpan dict diurutkan saat Anda menambahkan item dan mungkin perlu menambahkan item di masa depan:

Bangun dictmulai dari awal. Memiliki struktur data kedua, daftar, dengan daftar kunci Anda. Paket bisect memiliki fungsi insort yang memungkinkan memasukkan ke dalam daftar yang disortir, atau mengurutkan daftar Anda setelah benar-benar mengisi dict Anda. Sekarang, ketika Anda mengulangi dict Anda, Anda sebaliknya beralih ke daftar untuk mengakses setiap kunci secara berurutan tanpa khawatir tentang representasi struktur dict (yang tidak dibuat untuk menyortir).

demongolem
sumber
-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)
pengguna7070507
sumber
3
Ada 14 jawaban lain. Bisakah Anda menjelaskan sedikit kode Anda dan mengapa itu mungkin lebih baik daripada solusi lain?
FelixSFD
Downvoted - Kode yang cukup tidak terbaca dengan nama variabel pendek yang tidak berarti l, l2, l3. Tampaknya merupakan upaya pada algoritma tidak langsung dan tidak efisien tanpa pengetahuan tentang fungsi standar python, dan dalam hal apapun tidak berfungsi ketika diuji pada contoh kecil di posting asli.
Kapten Lepton