Bir sözlüğü değere göre nasıl sıralayabilirim?


3422

Bir veritabanındaki iki alandan okunan değerler sözlüğü var: bir dize alanı ve sayısal alan. Dize alanı benzersizdir, bu yüzden sözlüğün anahtarıdır.

Anahtarları sıralayabilirim, ancak değerlere göre nasıl sıralayabilirim?

Not: Yığın Taşması sorusunu burada okudum Sözlüklerin listesini sözlüğün değerine göre nasıl sıralayabilirim? ve muhtemelen bir sözlük listesine sahip olmak için kodumu değiştirebilirim, ama gerçekten bir sözlük listesine ihtiyacım olmadığından, artan veya azalan düzende sıralamak için daha basit bir çözüm olup olmadığını bilmek istedim.


9
Sözlük veri yapısının doğal sırası yoktur. Bunu yineleyebilirsiniz, ancak yinelemenin belirli bir siparişi takip edeceğini garanti edecek hiçbir şey yoktur. Bu tasarım gereğidir, bu nedenle en iyi bahsiniz temsil için anohter veri yapısını kullanmaktır.
Daishiman

135
"sort ()" sözlükler üzerinde çalışabilir (ve sıralanmış anahtarların bir listesini döndürür), bu yüzden bunun farkında olduğunu düşünüyorum. Programını bilmeden, birine yanlış veri yapısını kullandıklarını söylemek saçmadır. Hızlı aramalar zamanın% 90'ına ihtiyacınız olan şeyse, bir diksiyon muhtemelen istediğiniz şeydir.
bobpaul

Sözlükleri sıralamak için üç
çıktının hepsi

2
@Daishiman Temel sınıf sipariş edilmemiş olabilir, ancak OrderedDict elbette.
Taylor Edmiston

1
Python 3.6 ve sonraki sürümlerinde sözlükler ekleme sırasını korur. Bu, elbette, onları değere göre sıralama olasılığı ile aynı değildir, ancak öte yandan, "sözlük veri yapısının doğası gereği olmadığını" söylemek artık geçerli değildir.
Konrad Kocik

Yanıtlar:


4948

Python 3.6 ve üzeri

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}

Yaşlı Python

Bir sözlüğü sıralamak mümkün değildir, sadece sıralanan bir sözlüğün temsilini almak mümkündür. Sözlükler doğal olarak düzensizdir, ancak listeler ve tuples gibi diğer türler değildir. Dolayısıyla, sıralı değerleri temsil etmek için sıralı bir veri türüne ihtiyacınız vardır;

Örneğin,

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

sorted_xher bir gruptaki ikinci öğeye göre sıralanmış grupların bir listesi olacaktır. dict(sorted_x) == x.

Ve değerler yerine anahtarları sıralamak isteyenler için:

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

Python3 olarak veri açma beri izin verilmez [1] Kullanabileceğimiz

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

Çıktının bir dikte olarak olmasını istiyorsanız şunları kullanabilirsiniz collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)

43
değer şemalarına göre çeşitli sözlük sıralamalarındaki zamanlamalar için: writeonly.wordpress.com/2008/08/30/…
Gregg Lind

164
sorted_x.reverse()azalan bir sipariş verecek (ikinci tuple elemanı tarafından)
saidimu apale 5

414
saidimu: Zaten kullandığımızdan sorted(), reverse=Truetartışmayı geçmek çok daha verimli .
rmh

121
Python3 olarak bir lambda kullanılır: sorted(d.items(), key=lambda x: x[1]). Bu python 2.x ile çalışır mı?
Keyo

84
OrderedDict, koleksiyonlara 2.7'de eklendi. Gösterilen sıralama örneği: docs.python.org/library/…
monkut

1262

Kadar basit: sorted(dict1, key=dict1.get)

Aslında, bir "sözlük değerlerine göre sırala" yapmak mümkündür. Son zamanlarda bir Code Golf (Stack Overflow soru Kodu golf: Kelime frekans grafiği ) bunu yapmak zorunda kaldı . Kısaltılmış, sorun aynıydı: bir metin verildiğinde, her kelimenin ne sıklıkta karşılaşıldığını sayın ve azalan sıklığa göre sıralanmış en iyi kelimelerin bir listesini görüntüleyin.

Anahtar sözcük olarak sözcükleri ve her kelimenin değer sayısını değer olarak içeren bir sözlük oluşturursanız, burada şu şekilde basitleştirilir:

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

ardından, kullanım sıklığına göre sıralanan kelimelerin bir listesini elde edebilirsiniz sorted(d, key=d.get)- sıralama, sözlük anahtarları üzerinde yinelenir ve sözcük oluşumlarının sayısını bir sıralama anahtarı olarak kullanır.

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

"Ayrıntılı bir sözlüğü kolayca anahtarla sıralayabilirim, ama değere göre nasıl sıralayabilirim" ile insanların sık sık ne anlama geldiğini göstermek için bu ayrıntılı açıklamayı yazıyorum - ve orijinal yazının böyle bir sorunu çözmeye çalıştığını düşünüyorum. Ve çözüm, yukarıda gösterildiği gibi, değerlere dayalı olarak anahtarların bir listesini yapmaktır.


31
Bu da iyidir ancak key=operator.itemgetter(1)verimlilik için daha ölçeklenebilir olmalıdırkey=d.get
smci

3
@raylu itemgetter kullanarak "çalışmıyor" davranışını gözlemliyorum: ----- 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 Her kodu çalıştırdığımda sonuçlar değişiyor: tuhaf . (üzgünüm, düzgün görüntülenmesi için kod alınamıyor)
bli

12
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True)ve for key, val in sorted_keys: print "%s: %d" % (key, val)- itemgetter çağrıldığında bir işlev oluşturur, doğrudan örneğinizdeki gibi kullanmazsınız. Ve bir
dikte

18
Ben size anlatmak için gelecekten geldim collections.Counter, hangi most_commonilginizi çekebilir bir yöntem var :)
Eevee

2
@Eevee - f2f dışı kısa yorumlarda yanlış anlaşılma riski var. Amuzing tidbit: collections.Counterneredeyse 7 yıl önce piyasaya sürülen 2.7'de eklendi! (Ben o zaman bilmiyordum - artı ben oyunun tek saplantı olan kısalık amacıyla kod golf kaçınmış olurdu)
Nas Banov

857

Kullanabilirsin:

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

Bu, sözlüğü sözlük içindeki en küçükten en büyüğe her girişin değerlerine göre sıralar.

Azalan düzende sıralamak için şunu ekleyin reverse=True:

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

Giriş:

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

Çıktı:

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

Gördüğüm kadarıyla ( docs.python.org/2/library/… ), OrderedDict adında bir sınıf var ve bunlar hala sözlükken sıralanabiliyor ve düzeni koruyabiliyor. Kod örneklerinden, sıralamak için lambda kullanabilirsiniz, ama ben şahsen denemedim: P
UsAndRufus

53
Ben tercih ediyorum key=lambda (k, v): vşahsen
Claudiu

35
@Claudiu Bu (k, v)sözdizimini de seviyorum, ancak tuple parametresinin paketinin kaldırılmasının kaldırıldığı Python 3'te mevcut değil .
Bob Stein

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

3
Hayır. Sıralanmış bir tuples listesinden bir diksiyon oluşturmak siparişi tekrar öldürür ...
Jean-François Fabre

233

Diktler sıralanamaz, ancak onlardan sıralı bir liste oluşturabilirsiniz.

Dikte değerlerinin sıralı bir listesi:

sorted(d.values())

Değere göre sıralanmış (anahtar, değer) çiftlerinin bir listesi:

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

Aynı değere sahip anahtarlar hangi sıraya yerleştirilir? Listeyi önce tuşlara, sonra değerlere göre sıraladım, ancak aynı değere sahip tuşların sırası kalmıyor.
SabreWolfy

1
Dicts artık CPython 3.6 ve 3.7
Boris

161

Son Python 2.7'de, öğelerin eklendiği sırayı hatırlayan yeni OrderedDict tipine sahibiz .

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

Orijinalden yeni bir sıralı sözlük yapmak için değerlere göre sıralayın:

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

OrderedDict normal bir dikte gibi davranır:

>>> 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
Sorunun konusu bu değil - anahtarların sırasını korumak değil, "değere göre sıralama" ile ilgili
Nas Banov

10
@Nas Banov: anahtar ile sıralama DEĞİLDİR. sırayla sıralama, biz öğeleri oluşturmak. bizim durumumuzda, değere göre sıralıyoruz. ne yazık ki, 3 maddeli dikti ne yazık ki seçildi böylece sipariş aynıydı, değer ve anahtar ile voth sıralandığında, bu yüzden örnek dikti genişletti.
mykhal

sorted(d.items(), key=lambda x: x[1])Ne xanlama geldiğini açıklayabilir misiniz , neden x[1]lambda'ya gidebilir ? Neden olamaz x[0]? Çok teşekkür ederim!
JZAU

1
@Boern d.items()liste benzeri bir kapsayıcı döndürür (key, value). [0]grubun ilk öğesine - anahtar - ve [1]ikinci öğeye - değere erişir.
BallpointBen

2
Not: (a CPython / PyPy uygulama ayrıntı olarak) 3.6 itibarıyla ve (Python dil garantisi olarak) 3.7 itibariyle, sade dict, sadece yerini alabilir böylece yerleştirme yanı emretmesi OrderedDictile dictkodu için Modern Python üzerinde çalışan. OrderedDictmevcut dict( move_to_end/ ile popitem) sırasını yeniden düzenlemeniz veya siparişe duyarlı olması için eşitlik karşılaştırmaları yapmanız gerekmedikçe artık gerçekten gerekli değildir . Ovadan çok daha fazla bellek kullanır dict, bu yüzden eğer yapabiliyorsanız, dictyol budur.
ShadowRanger

104

GÜNCELLEME: 5 ARALIK 2015 Python 3.5 kullanarak

Kabul edilen cevabı faydalı bulduğum halde , standart kütüphane koleksiyonları modülünden OrderedDict'e tam olarak bu tür bir sorunu çözmek için tasarlanmış, uygulanabilir ve modern bir alternatif olarak başvurmak için güncellenmediğine şaşırdım .

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

Resmi OrderedDict belgeleri de çok benzer bir örnek sunuyor, ancak sıralama işlevi için bir lambda kullanıyor:

# 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

Hank Gay'in cevabı ile hemen hemen aynı :

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

Veya John Fouhy tarafından önerildiği gibi biraz optimize edildi:

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

9
..ve Hank Gay'in cevabında olduğu gibi, köşeli parantezlere ihtiyacınız yok. sort (), bir jeneratör ifadesi gibi herhangi bir yinelenebilir bir şekilde alır.
John Fouhy

(Anahtar, değer) elde etmek için (değer, anahtar) tuple elemanlarını değiştirmeniz gerekebilir. Daha sonra başka bir liste kavrayışı gereklidir. [(key, value) for (value, key) in sorted_list_of_tuples]
saidimu apale

Hayır, köşeli parantez bırakmak daha iyidir, çünkü sortedlisteyi yine de yeniden oluşturmak zorunda kalacaksınız ve gencomp'dan yeniden inşa etmek daha hızlı olacaktır. Codegolfing için iyi, hız için kötü. Çirkin ([])sürümü sakla .
Jean-François Fabre

75

Namedtuple kullanmak genellikle çok kullanışlı olabilir . Örneğin, anahtarlar olarak 'ad' ve değerler olarak 'puan' sözlüğünüz var ve 'puan' üzerinde sıralamak istiyorsunuz:

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

önce en düşük puanla sıralama:

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

önce en yüksek puanla sıralama:

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

Şimdi adını ve puanını alabilirsiniz, diyelim ki en iyi ikinci oyuncu (index = 1) Pythonically şöyle:

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

Nasıl tekrar sözlüğe dönüştürebilirim?
rowana

as_list = [d.items () içindeki (k, v) oyuncusu (v, k)] as_dict = dict (as_list'deki p için p.name, p.score)
Remi

72

Python 3.6 itibarıyla yerleşik dict sıralanır

İyi haber, bu nedenle OP'nin anahtarlar olarak benzersiz dize kimlikleri ve yerleşik bir Python v3.6 + dict'e değerler olarak sayısal değerler içeren bir veritabanından alınan eşleme çiftlerinin orijinal kullanım durumu, artık ekleme sırasına uymalıdır.

Bir veritabanı sorgusundan elde edilen iki sütun tablosu ifadesini şöyle söylerseniz:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

k_seq ve v_seq olmak üzere iki Python tuplesinde (sayısal indeks ile hizalanmış ve aynı kurs uzunluğuyla) saklanırsa, o zaman:

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

Daha sonra şu şekilde çıktı almanıza izin verin:

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

bu durumda (yeni Python 3.6+ yerleşik dikte için!):

foo 0
bar 1
baz 42

aynı sırayla

Makinemde Python 3.5 kurulumunda şu anda şunları sağlar:

bar 1
foo 0
baz 42

Detaylar:

2012'de Raymond Hettinger tarafından önerildiği gibi ( "daha hızlı yinelemeli daha kompakt sözlükler" ile python-dev'e cf. postası ) ve şimdi (2016'da) Victor Stinner tarafından "Python 3.6 dict kompakt ve özel bir sürüm alır ve anahtar kelimeler " sorun 27350'nin düzeltilmesi / uygulanması nedeniyle sipariş edilir " Kompakt ve düzenli dikte " Python 3.6 şimdi ekleme siparişi korumak için yerleşik bir dikte kullanmak mümkün olacak!

Umarım bu, ilk adım olarak ince bir katman OrderedDict uygulamasına yol açacaktır. @ JimFasarakis-Hilliard'ın belirttiği gibi, bazıları gelecekte de OrderedDict tipi için kullanım durumlarını görüyor. Bence Python topluluğu, zamanın testine dayanıp dayanamayacağını ve sonraki adımların ne olacağını dikkatlice inceleyecek.

Aşağıdakilerin istikrarlı bir şekilde sıralanmasıyla açılan olasılıkları kaçırmamak için kodlama alışkanlıklarımızı yeniden düşünme zamanı:

  • Anahtar kelime bağımsız değişkenleri ve
  • (ara) dik depolama

Birincisi, bazı durumlarda işlevlerin ve yöntemlerin uygulanmasında gönderimi kolaylaştırdığı için.

İkincisi, dictboru hatlarının işlenmesinde ara depo olarak daha kolay kullanılmasını teşvik ettiği için .

Raymond Hettinger , San Francisco Python Meetup Group 2016-DEC-08 sunumundan “ Python 3.6 Sözlüklerinin Arkasındaki Teknoloji ” yi açıklayan belgeler sunmuştur .

Ve belki de oldukça fazla Stack Overflow yüksek süslü soru ve cevap sayfaları bu bilgilerin varyantlarını alacak ve birçok yüksek kaliteli cevap da sürüm başına güncelleme gerektirecektir.

Uyarı Emptor (aynı zamanda aşağıdaki güncelleme 2017-12-15'e bakın):

@Ajcr'ın haklı olarak belirttiği gibi: "Bu yeni uygulamanın siparişi koruyan yönü bir uygulama detayı olarak kabul edilir ve buna güvenilmemelidir." ( whatsnew36'dan ) nit toplama değil, ancak alıntı biraz kötümser ;-) kesildi. Şu şekilde devam ediyor "(bu gelecekte değişebilir, ancak mevcut ve gelecekteki tüm Python uygulamaları için düzeni koruyan anlambilimi zorunlu kılmak için dil spesifikasyonunu değiştirmeden önce bu yeni dict uygulamasının birkaç sürüm için dilde olması arzu edilir; 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). "

Bazı insan dillerinde (örn. Almanca) olduğu gibi, kullanım dili şekillendirir ve irade şimdi bildirilmiştir ... whatsnew36'da .

2017-12-15 Güncellemesi:

Python-dev listesine bir postada Guido van Rossum şunları söyledi:

Öyleyse yap. "Dict ekleme emrini koruyor" kararıdır. Teşekkürler!

Bu nedenle, dict ekleme siparişinin 3.6 CPython yan etkisi artık dil spesifikasyonunun bir parçası haline geliyor (ve artık sadece bir uygulama detayı değil). Bu posta dizisi, collections.OrderedDicttartışma sırasında Raymond Hettinger tarafından hatırlatıldığı gibi bazı ayırt edici tasarım hedeflerini de ortaya çıkardı .


15
Bağlandığınız 'neyin yeni' sayfasındaki uyarı vurgulanmalıdır: Bu yeni uygulamanın siparişi koruyan yönü bir uygulama ayrıntısı olarak kabul edilir ve bu bilgilere güvenilmemelidir . Hiç kimse, dicttürün kodlarındaki ekleme sırasına saygı göstereceğini varsaymamalıdır . Bu dilin tanımının bir parçası değildir ve uygulama gelecekteki herhangi bir sürümde değişebilir. OrderedDictSiparişi garanti etmek için kullanmaya devam edin .
Alex Riley

@ajcr ihtar için teşekkürler, çok takdir - suratlarıma suratlar ve belki de dokunduğum için, bunlar belirtilmelidir, değişiklik büyüktür, ancak elbette, sadece CPython (referans uygulaması) ve PyPy için mevcuttur. Tamamen farklı bir şey için ... İnsan-makine talimatlarını kodlarken nadiren uygulama dışı ayrıntılarla konuşurum. Sadece Jython ;-) olsaydı ... Yazmaya cesaret edemezdim.
Seyreltici

OrderedDictkesinlikle bırakılmayacak; bunun yerine, geçerli dikte uygulaması etrafında ince bir sarıcı haline gelecektir (böylece daha kompakt hale geleceğini de ekleyebilirsiniz). Kullanılmayan ImportErrorokuyucuları yanıltması nedeniyle bu snippet'i, ile eklemek en iyi fikir değildir OrderedDict.
Dimitris Fasarakis Hilliard

@ JimFasarakis-Hilliard geri bildiriminiz için teşekkür ederiz. "Oldukça iyi fikirler" beni güldürdü - geleceği tahmin etmek genellikle zor. Ama öneriniz kaynakları kontrol edecek, deneyecek ve cevabı buna göre güncelleyeceğim. Tekrar teşekkürler.
Seyreltici

8
@AlexRiley Bu uyarı artık doğru değil. Python3.7 sipariş edilen sözlükleri garanti eder.
gerrit

42

Aynı sorunu yaşadım ve şu şekilde çözdüm:

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

("Bir dikteyi sıralamak mümkün değildir" diye cevaplayanlar soruyu okumadılar! Aslında, "Anahtarları sıralayabilirim, ama değerlere göre nasıl sıralayabilirim?" tuşlar değerlerinin değerine göre sıralanır.)

Lütfen siparişin iyi tanımlanmadığına dikkat edin (aynı değere sahip tuşlar, çıktı listesinde isteğe bağlı bir sırada olacaktır).



Hem sözlüğü yinelediğinizi hem de değerleri anahtarlarıyla getirdiğinizi unutmayın, bu yüzden performans açısından bu en uygun çözüm değildir.
Ron Klein

1
@Dejell: Katkıda bulunanın dediği gibi, soruyu "değerlere göre sıralanmış anahtarların listesini alabilir miyim" şeklinde yorumlar. Sonuçtaki değerlere ihtiyacımız yok, sözlükte var.
Max

36

Değerler sayısalsa Counter, koleksiyonlardan da kullanabilirsiniz .

from collections import Counter

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

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

sözlüğünüz >>> x = {'merhaba': 1, 'python': 5, 'dünya' ise: 300}
James Sapam

@yopy Counter({'hello':1, 'python':5, 'world':300}).most_common()verir [('world', 300), ('python', 5), ('hello', 1)]. Bu aslında herhangi bir sıralanabilir değer türü için işe yarar ( diğer pek çok Sayaç işlemi değerlerin ints ile karşılaştırılabilir olmasını gerektirmesine rağmen ).
lvc

34

Python 2.7'de şunları yapın:

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

kopyala yapıştır: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Zevk almak ;-)


25

Bu kod:

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

Sonuçlar burada:

orijinal

{'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}

rütbe

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

Aşağıdaki yaklaşımı deneyin. Aşağıdaki verilerle mydict adlı bir sözlük tanımlayalım:

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

Sözlüğü anahtarlara göre sıralamak isterse, aşağıdakine benzer bir şey yapılabilir:

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

Bu, aşağıdaki çıktıyı döndürmelidir:

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

Öte yandan, bir sözlüğü değere göre (soruda sorulduğu gibi) sıralamak isterse, aşağıdakiler yapılabilir:

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

Bu komutun sonucu (sözlüğü değere göre sıralamak) aşağıdakileri döndürmelidir:

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

Müthiş! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]):bir alt anahtara göre sıralamanızı sağlar
Andomar

bana Python3 lambda yakın sözdizimi hatası veriyor
Suleman Elahi

21

Python 3.6'dan başlayarak, dictnesneler artık ekleme siparişine göre sıralanmıştır. Resmi olarak Python 3.7 teknik özelliklerinde.

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

Ondan önce kullanmak zorundaydın OrderedDict.

Python 3.7 belgeleri diyor:

Sürüm 3.7'de değiştirildi: Sözlük siparişinin kampanya siparişi olması garanti edilir. Bu davranış, 3.6'dan CPython'un uygulama ayrıntısıydı.


harika çalışıyor! dict(sorted(words.items(), key=lambda x: x[1], reverse=True))DESC için
vizyourdata

20

"Tersine çevrilmiş bir dizin" de oluşturabilirsiniz.

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

Şimdi tersiniz değerlere sahip; her değerin geçerli anahtarların bir listesi vardır.

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

19

Collections.Counter kullanabilirsiniz . Bunun hem sayısal hem de sayısal olmayan değerler için çalışacağını unutmayın.

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


15

Kalıcı olarak değere göre sıralanmış bir sözlük olan bir atlama diktesi kullanabilirsiniz .

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

Eğer kullanırsanız keys(), values()yaitems() o zaman değeriyle sıralanmış sırayla yineleme edeceğiz.

Atlama listesi veri yapısı kullanılarak uygulanır .


sıralama düzenini değiştirebilir miyiz?
Suleman Elahi

afaik sipariş tersine çevirmek için değerlerinizi reddetmek gerekir
malthe

vay, böyle düşünüyorum ... teşekkürler.
Suleman Elahi

14

Ayrıca, tuşa geçirilebilen özel işlevi de kullanabilirsiniz.

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
soru şuydu: anahtarlara göre değil, değere göre sırala ... Bir işlevi görmeyi seviyorum. Koleksiyonları içe aktarabilirsiniz ve elbette sıralı olarak kullanabilirsiniz (data.values ​​())
Remi

10

Dilettant'ın işaret ettiği gibi , Python 3.6 şimdi siparişi koruyacak ! Bir yinelenebilir (sıralama, liste, dikte) sıralama kolaylaştırır yazdığım bir işlevi paylaşmak düşündüm. İkinci durumda, anahtarlara veya değerlere göre sıralama yapabilirsiniz ve sayısal karşılaştırmayı dikkate alabilir. Sadece> = 3.6!

Örneğin dizeleri ve girişleri içeren bir yinelemeli sıralamada kullanmayı denediğinizde, sort () başarısız olur. Elbette str () ile dize karşılaştırmasını zorlayabilirsiniz. Ancak, bazı durumlarda, gerçek sayı karşılaştırması yapmak istediğiniz yerden 12küçüktür 20(dize karşılaştırmasında durum böyle değildir). Bu yüzden aşağıdakileri buldum. Açık sayısal karşılaştırma istediğinizde, num_as_numtüm değerleri kayan noktaya dönüştürmeye çalışarak açık sayısal sıralama yapmaya çalışacak bayrağı kullanabilirsiniz . Bu başarılı olursa, sayısal sıralama yapar, aksi takdirde dize karşılaştırmasına başvurur.

Iyileştirme veya push istekleri için yorumlar hoş geldiniz.

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

İşte d.values()ved.keys() üzerinde zip kullanan bir çözüm . Bu bağlantıdan birkaç satır aşağı (Sözlük görüntüleme nesnelerinde):

Bu, zip () kullanarak (değer, anahtar) çiftlerinin oluşturulmasına izin verir: pairs = zip (d.values ​​(), d.keys ()).

Böylece aşağıdakileri yapabiliriz:

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

Tabii ki unutmayın, kullanmanız gerekir, OrderedDictçünkü normal Python sözlükleri orijinal düzeni korumaz.

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

Python 2.7 veya daha üst sürümünüz yoksa, yapabileceğiniz en iyi şey bir jeneratör işlevindeki değerleri yinelemektir. (Burada OrderedDict2.4 ve 2.6 için bir var , ancak

a) Ne kadar iyi çalıştığını bilmiyorum

ve

b) Tabii ki indirip yüklemelisiniz. Yönetici erişiminiz yoksa, seçeneğin kullanımdan korkuyorum.)


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

Ayrıca her değeri yazdırabilirsiniz

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

Python 3.0 veya üstünü kullanmıyorsanız, lütfen yazdırdıktan sonra parantezleri kaldırmayı unutmayın.


normal Python sözlükleri orijinal düzeni korumaz - Python 3.7'den itibaren.
gerrit

7

Kullanım ValueSortedDict gelen 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

3.1.x sürümünde çalışır:

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

6

Python'dan Herkes için ilgili becerileri öğrendim .

Sözlüğü sıralamanıza yardımcı olması için geçici bir liste kullanabilirsiniz:

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

Listeyi azalan düzende sıralamak istiyorsanız, orijinal sıralama satırını şu şekilde değiştirin:

tmp = sorted(tmp, reverse=True)

Liste kavrayışı kullanıldığında, tek astar:

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

Örnek Çıktı:

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

bu değerlere göre değil, anahtarlara göre sıralamadır.
Rubel

İlk formatta yazdırmak istiyorsanız şunları yapmalısınız: yazdır (v için k, [(k, v) için sıralanmış (([(v, k) için k, v için d.items ()])])). Çıktı: [('turuncu', 1.0), ('elma', 500.1), ('ananas', 789.0), ('muz', 1500.2)]. V için [, k, v) ile sıralanmış olarak ([(v, k) için k, v için d.items ()], ters = Doğru)] çıktı: [('muz', 1500.2), ('ananas', 789.0), ('elma', 500.1), ('turuncu', 1.0)]
Hermes Morales

5

Bir dikte boyunca yineleme yapın ve değerleri azalan sırada sıralayı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

Değerleriniz tamsayı ise ve Python 2.7 veya daha yenisini kullanıyorsanız, collections.Counteryerine kullanabilirsiniz dict. most_commonYöntem size değerine göre sıralanmış tüm öğeleri verecektir.


5

Bütünlük uğruna, heapq kullanarak bir çözüm gönderiyorum . Bu yöntemin hem sayısal hem de sayısal olmayan değerler için çalışacağını unutmayın

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

Python'un eski sürümleriyle geriye dönük uyumluluğu korumak için gereksinimler nedeniyle OrderedDict çözümünün çok akılsız olduğunu düşünüyorum. Python 2.7 ve daha eski sürümlerle çalışan bir şey istiyorsunuz.

Ancak başka bir cevapta bahsedilen koleksiyon çözümü kesinlikle mükemmeldir, çünkü sözlükler söz konusu olduğunda son derece önemli olan anahtar ve değer arasındaki bağlantıyı yeniden eğitirsiniz.

Başka bir cevapta sunulan bir numaralı seçeneğe katılmıyorum, çünkü anahtarları atıyor.

Yukarıda belirtilen çözümü (aşağıda gösterilen kod) kullandım ve hem anahtarlara hem de değerlere erişimi korudum ve benim durumumda değerler değerler üzerindeydi, ancak önem, değerleri sipariş ettikten sonra anahtarların sıralamasıydı.

from collections import Counter

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


>> [('python', 5), ('world', 3), ('hello', 1)]
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.