Bir sözlüğü anahtar ile nasıl sıralayabilirim?


940

Gitmek için güzel bir yol ne olabilir {2:3, 1:89, 4:5, 3:0}için {1:89, 2:3, 3:0, 4:5}?
Bazı yayınları kontrol ettim ama hepsi tuples döndüren "sıralanmış" operatörünü kullanıyor.


39
Sözlükler özünde ayrılmaz. Gösterilen sözlüğü başka bir konudur. Her neyse, gerçekten ne için sıralamanız gerekiyor?
Karl Knechtel

15
sözlükler sıralanmamış. sadece öyle değiller. d öğesinin sözlüğünüzün adı olduğunu varsayarak sıralı kullanarak (d anahtar (d.keys ()) için) gibi sıralı bir şekilde kullanmak zorunda olduğunuz öğeleri sırayla yapmak istiyorsanız
Ryan Haining

3
@KarlKnechtel - benim kullanım durumum ilkel bir menüye sahip bir CLI uygulaması ve menü seçenekleri anahtar olarak sözlükte olmasıdır. Kullanıcıların akıl sağlığı için anahtarları alfabetik olarak göstermek istiyorum.
Randy


4
Diktelerin artık ekleme siparişine göre sıralandığını unutmayın (python 3.6+). Aşağıdaki bazı cevaplar buna işaret ediyor.
matiasg

Yanıtlar:


940

Standart Python sözlükleri sıralanmamıştır. (Anahtar, değer) çiftlerini dictsıralasanız bile, sıralamayı koruyacak şekilde saklayamazsınız .

En kolay yol, OrderedDictöğelerin yerleştirilme sırasını hatırlayan kullanmaktır :

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

Yolun odyazdırılmasını boş verin; beklendiği gibi çalışacaktır:

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

Python 3 kullanıcıları için .items()bunun yerine aşağıdakini kullanmanız gerekir .iteritems():

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

1
Bunu kullandım ve işe yarıyor, daha fazla kod ve fazlalık olduğunu tahmin ediyorum, ancak işi bitirdi, sıralanmamış anahtar d = {2: 3, 1:89, 4: 5, 3: 0} orderedDict = {} (d.iterkeys ()): orderedDict [anahtar] = d [anahtar]
Antony

4
@achrysochoou: eğer bu işe yaradıysa, tamamen şanslı olmalıydı. Size söylendiği gibi, anahtarları sıralı veya rasgele bir şekilde atasanız da, normal sözlüklerin sıralama kavramı yoktur.
Ricardo Cárdenes

21
Python 3.7+ için:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618

10
Şimdi varsayılan olarak sipariş verdiğinden beri :-)
Aneuway

3
Python 3.7.4 kılavuzundan: "Bir sözlükte liste (d) yapılması, sözlükte kullanılan tüm tuşların ekleme sırasında bir listesini döndürür". Bu nedenle ekleme talimatı korunan bir şeydir ve güvenebiliriz.
Mostafa Hadian

415

Sözlüklerin kendileri gibi öğeleri sipariş etmediler, bunları bazı siparişlere yazdırmak istiyorsanız, bazı örnekler:

Python 2.4 ve üstü sürümlerde:

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

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

verir:

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

(Python 2.4'ün altında :)

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

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


2
OrderedDict'i NPE'nin cevabında olduğu gibi python 2.4+'de de kullanabilirsiniz
Radtek

1
ve item () kullanıyorsanız bunu yapabilirsinizfor key, value in sorted(mydict.items())"
beep_check

Sözlükler kendileri gibi öğeleri sipariş yok -> artık doğru değil!
minexew

Nasıl olur da açıklayabilir misin?
James

204

Gönderen Python'un collectionskütüphane dokümantasyon :

>>> 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
müthiş! Çocuklar siparişi tersine çevirmek istiyorsanız (azalan TO) o zaman sadece reverse=Trueörneğin ekleyinOrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
benscabbia

1
PyCharm'da, ne sözlük kullanırsam kullanın, her zaman bu uyarıyı alırım:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter

153

CPython / PyPy 3.6 ve herhangi bir Python 3.7 veya üstü için bu kolayca yapılabilir:

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

3
Aynı şeyi yazmanın başka bir yolu da bir kavrama kullanmaktır:{key:d[key] for key in sorted(d.keys())}
flow2k

41

Anahtarları otomatik olarak sıralanmış düzende tutan sözlük uygulamaları sağlayan bir dizi Python modülü vardır. Pure-Python ve C kadar hızlı uygulamalar olan sortcontainers modülünü düşünün . Birbirlerine göre kıyaslanan diğer popüler seçeneklerle de bir performans karşılaştırması var.

Anahtar / değer çiftlerini sürekli olarak eklemeniz ve kaldırmanız gerekirse, sıralı bir diksiyon kullanmak yetersiz bir çözümdür.

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

SortedDict türü, yerleşik dikt türüyle mümkün olmayan dizinli konum aramalarını ve silmeyi de destekler.

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

32

basitçe:

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

for k,v in sd:
    print k, v

Çıktı:

1 89
2 3
3 0
4 5

6
sdsözlüklerin değil tuples'ların listesidir. (yine de faydalı.)
nischi

24

Diğerlerinin de belirttiği gibi, sözlükler doğal olarak düzensizdir. Sorun sadece Ancak, görüntüleme belli bir düzen içinde sözlükleri, sen geçersiz kılabilirsiniz __str__bir sözlük alt sınıfta yöntemi ve yerleşiğine ziyade bu sözlük sınıfını kullanın dict. Örneğin.

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}

Not, bu, tuşların nasıl saklandığı, üzerlerinde yinelendiğinde geri gelme sırası vb., Sadece printpython konsolunda veya python konsolunda nasıl gösterildikleri hakkında hiçbir şey değiştirmez .


19

Başka bir yol buldum:

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

upd:
1. Bu da iç içe nesneleri sıralar (teşekkürler @DanielF).
2. Python sözlükleri sıralanmamış olduğundan, bu yalnızca yazdırma için kullanılabilir veya yalnızca str'ye atanabilir.


Ancak bu, istenmeyebilecek iç içe nesnelerin anahtarlarını da sıralar.
Daniel F

Bunun sadece sözlükleri sıraladığını, listeleri değil sıraladığını unutmayın, örn. Dict.keys () bir liste olduğu için sıralanmayacaktır.
Andrew

16

Python 3'te.

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

verir

1 89
2 3
3 0
4 5

13

Python sözlüğü Python 3.6'dan önce sıralanmamıştı. Python 3.6'nın CPython uygulamasında sözlük ekleme sırasını korur. Python 3.7'den itibaren bu bir dil özelliği haline gelecek.

Python 3.6 değişiklik günlüğünde ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

Bu yeni uygulamanın siparişi koruyan yönü bir uygulama detayı olarak kabul edilir ve buna güvenilmemelidir (bu gelecekte değişebilir, ancak dil spesifikasyonunu değiştirmeden önce bu yeni dict uygulamasının birkaç sürüm için dilde olması arzu edilir. mevcut ve gelecekteki tüm Python uygulamaları için siparişi koruyan semantikleri zorunlu kılmak için; bu aynı zamanda rastgele yineleme sırasının hala geçerli olduğu dilin eski sürümleriyle geriye dönük uyumluluğu korumaya yardımcı olur, örneğin Python 3.5).

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

Bir sözlükte liste (d) gerçekleştirilmesi, sözlükte kullanılan tüm tuşların ekleme sırasına göre bir listesini döndürür (sıralanmasını istiyorsanız, bunun yerine sıralı (d) işlevini kullanın).

Önceki sürümlerden farklı olarak, bir dikteyi Python 3.6 / 3.7'den sonra sıralayabilirsiniz. İçindeki alt dikdörtgeni içeren iç içe geçmiş bir diktüyü sıralamak istiyorsanız, şunları yapabilirsiniz:

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

Burada python dict kullanarak anahtar sıralamak için bazı basit bir çözüm buldum pprint. Örneğin.

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

ama pprint kullanırken sıralı diksiyon döndürecektir

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

10

Bir sözlüğü sıralamanın kolay bir yolu vardır.

Sorunuza göre,

Çözüm şudur :

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

(Burada c, sözlüğünüzün adıdır.)

Bu program aşağıdaki çıktıyı verir:

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

istediğin gibi.

Başka bir örnek:

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

Çıktı verir:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

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

Çıktı verir:[18, 24, 32, 36, 41]

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

Çıktı verir:

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

Bu nedenle, tuşları, değerleri ve öğeleri değiştirerek, istediğiniz gibi yazdırabilirsiniz.


8

Tam olarak ne istediğinizi üretecektir:

 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}

Ancak bu, bunu yapmanın doğru yolu değildir, çünkü Son zamanlarda öğrendiğim farklı sözlüklerle farklı bir davranış gösterebilir. Bu nedenle Tim tarafından burada paylaştığım Sorgu'nun cevabında mükemmel bir yol önerildi.

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

"Farklı sözlüklerle farklı davranışlar göstermek" ne demektir? Sıralananların işleyemediği "farklı davranış" nedir?
ingyhere

6

En kolay şey, dikteyi anahtarla sıralamak ve sıralanan anahtarı: değer çiftini yeni bir dikte içine kaydetmek.

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]

Netleştirmek için:

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

Geçerli sözlüğü anahtarınıza göre sorunuza göre sıralayarak yeni bir sözlük oluşturabilirsiniz.

Bu senin sözlüğün

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

Bu d lambda işlevini kullanarak sıralayarak yeni bir sözlük d1 oluşturun

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

d1, {1: 89, 2: 3, 3: 0, 4: 5} olmalıdır ve d'deki tuşlara göre sıralanmalıdır.


5

Python dikteleri sıralanmamış. Genellikle, bu bir sorun değildir, çünkü en yaygın kullanım durumu arama yapmaktır.

İstediğinizi yapmanın en basit yolu collections.OrderedDict, öğeleri sıralı bir şekilde ekleyerek oluşturmaktır .

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

Yinelemeye ihtiyacınız varsa, yukarıdaki diğerlerinin önerdiği gibi, en basit yol sıralı anahtarlar üzerinde yineleme yapmaktır. örneklere

Tuşlara göre sıralanmış değerleri yazdırın:

# 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

Anahtarlara göre sıralanmış değerlerin listesini alın:

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

2
for k,value in sorted(d.items()):daha iyi: döngüde tekrar anahtar ile diksiyon erişmektan kaçınır
Jean-François Fabre

4

Tek satırlık dikte sıralama ile geldim.

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

Umarım bu yardımcı olacaktır.


4

Bu işlev, herhangi bir sözlüğü anahtarıyla yinelemeli olarak sıralar . Yani, sözlükteki herhangi bir değer de bir sözlükse, anahtarına göre de sıralanır. Eğer CPython 3.6 ya da daha üstünü çalıştırıyorsanız, bir dictyerine kullanmak için basit bir değişiklik OrderedDictyapılabilir.

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

Çocuklar işleri karmaşık hale getiriyorsunuz ... bu gerçekten basit

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

Çıktı:

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

Ben pprint sıraları görüntülemek için sözlükler bilmiyordum çünkü op, ama OP gerçekten sıralanmamış gelen sıralı dikte "gidiş" hakkında sordu, yani OP belki de sıralanmış anahtarlar gerektiren bazı algoritma için bellekte sıralanmış bir şey istiyor gibi görünüyor
Kaptan Lepton

Pprint hiçbiri döndürmediği için bu yöntem zincirleme atamaya izin vermeyecektir. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = pprint (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () Geri izleme (en son çağrı son olarak): <module> AttributeError: "NoneType" nesnesinde 'type' özelliği yok

2

En basit çözüm, dict anahtarının sıralanmış düzende bir listesini almanız ve daha sonra dict üzerinde yineleme yapmanızdır. Örneğin

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]

Aşağıdaki çıktı olacaktır (azalan sıra)

e 30
b 13
d 4
c 2
a 1

2

Bunu yapmanın kolay bir yolu:

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

2.7'deki iki yöntemin zamanlama karşılaştırması, bunların neredeyse aynı olduğunu gösterir:

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

Benim önerim, bir dikteyi sıralamanıza veya öğeleri eklerken bir dikteyi sıralamanıza izin verir ve gelecekte öğeler eklemeniz gerekebilir:

dictSiz ilerlerken sıfırdan bir yapı oluşturun . Anahtar listenizi içeren ikinci bir veri yapısına, bir listeye sahip olun. İkili paket, sıralı bir listeye eklenmeye veya diktenizi tamamen doldurduktan sonra listenizi sıralamaya izin veren bir içe aktarma işlevine sahiptir. Şimdi, diktenizi yinelediğinizde, dikte yapısının (sıralama için yapılmamıştır) gösterilmesi konusunda endişelenmeden, her bir tuşa sırayla erişmek için liste üzerinde tekrarlarsınız.


-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
14 cevap daha var. Kodunuzu biraz açıklayabilir misiniz ve neden diğer çözümlerden daha iyi olabilir?
FelixSFD

Downvoted - Kısa anlamsız değişken adları l, l2, l3 ile oldukça okunamayan kod. Python standart fonksiyonları hakkında bilgi sahibi olmayan dolaylı ve verimsiz bir algoritma girişimi gibi görünüyor ve orijinal yazıda küçük örnek üzerinde test edildiğinde her durumda işe yaramaz.
Kaptan Lepton
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.