Bagaimana cara saya mengurutkan kamus berdasarkan nilai?


3422

Saya memiliki kamus nilai yang dibaca dari dua bidang dalam database: bidang string dan bidang numerik. Bidang string unik, jadi itulah kunci kamus.

Saya bisa mengurutkan pada tombol, tetapi bagaimana saya bisa mengurutkan berdasarkan nilai-nilai?

Catatan: Saya telah membaca pertanyaan Stack Overflow di sini. Bagaimana cara saya mengurutkan daftar kamus berdasarkan nilai kamus? dan mungkin dapat mengubah kode saya untuk memiliki daftar kamus, tetapi karena saya tidak benar-benar membutuhkan daftar kamus saya ingin tahu apakah ada solusi yang lebih sederhana untuk mengurutkan baik dalam urutan naik atau turun.


9
Struktur data kamus tidak memiliki urutan bawaan. Anda dapat beralih melalui itu tetapi tidak ada yang menjamin bahwa iterasi akan mengikuti urutan tertentu. Ini adalah desain, jadi taruhan terbaik Anda mungkin menggunakan struktur data anohter untuk representasi.
Daishiman

135
"sortir ()" dapat beroperasi pada kamus (dan mengembalikan daftar kunci yang disortir), jadi saya pikir dia mengetahui hal ini. Tanpa mengetahui programnya, tidak masuk akal untuk memberi tahu seseorang bahwa mereka menggunakan struktur data yang salah. Jika pencarian cepat adalah yang Anda butuhkan 90% dari waktu, maka dikt mungkin yang Anda inginkan.
bobpaul

Ketiga output (kunci, nilai, keduanya) untuk kamus pengurutan dibahas di sini dalam gaya yang jelas dan ringkas: stackoverflow.com/questions/16772071/sort-dict-by-value-python
JStrahl

2
@Daishiman Kelas dasar mungkin tidak dipesan tetapi OrderedDict tentu saja.
Taylor Edmiston

1
Dalam Python 3.6+ kamus mempertahankan urutan penyisipan. Ini, tentu saja, tidak sama dengan kemungkinan mengurutkan mereka berdasarkan nilai, tetapi di sisi lain tidak lagi valid untuk mengatakan bahwa "struktur data kamus tidak memiliki urutan bawaan".
Konrad Kocik

Jawaban:


4955

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 yang lebih lama

Kamus tidak mungkin diurutkan, hanya untuk mendapatkan representasi kamus yang diurutkan. Kamus pada dasarnya tidak berurutan, tetapi jenis lain, seperti daftar dan tupel, tidak. Jadi, Anda memerlukan tipe data yang diurutkan untuk mewakili nilai yang diurutkan, yang akan menjadi daftar — mungkin daftar tupel.

Contohnya,

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

sorted_xakan menjadi daftar tupel yang diurutkan berdasarkan elemen kedua di setiap tupel. dict(sorted_x) == x.

Dan bagi mereka yang ingin mengurutkan pada kunci, bukan nilai:

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

Dalam Python3 karena membongkar tidak diperbolehkan [1] bisa kita gunakan

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

Jika Anda ingin output sebagai dict, Anda dapat menggunakan collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)

43

164
sorted_x.reverse()akan memberi Anda pemesanan menurun (oleh elemen tuple kedua)
saidimu apale

414
saidimu: Karena kita sudah menggunakan sorted(), jauh lebih efisien untuk meneruskan reverse=Trueargumen.
rmh

121
Dalam python3 saya menggunakan lambda: sorted(d.items(), key=lambda x: x[1]). Apakah ini akan bekerja di python 2.x?
Keyo

84
OrderedDict ditambahkan ke koleksi di 2.7. Contoh pengurutan ditampilkan di: docs.python.org/library/…
monkut

1264

Sesederhana: sorted(dict1, key=dict1.get)

Yah, sebenarnya mungkin untuk melakukan "urutkan berdasarkan nilai kamus". Baru-baru ini saya harus melakukan itu dalam Code Golf (Stack Overflow question Code golf: Word frequency chart ). Ringkasnya, masalahnya adalah dari jenis: diberi teks, menghitung seberapa sering setiap kata ditemui dan menampilkan daftar kata-kata teratas, diurutkan berdasarkan frekuensi yang menurun.

Jika Anda membuat kamus dengan kata-kata sebagai kunci dan jumlah kemunculan setiap kata sebagai nilai, disederhanakan di sini sebagai:

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

maka Anda bisa mendapatkan daftar kata-kata, diurutkan berdasarkan frekuensi penggunaan dengan sorted(d, key=d.get)- pengurutan yang dilakukan di atas tombol kamus, menggunakan jumlah kemunculan kata sebagai kunci pengurutan.

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

Saya menulis penjelasan terperinci ini untuk mengilustrasikan apa yang sering orang maksud dengan "Saya dapat dengan mudah mengurutkan kamus berdasarkan kunci, tetapi bagaimana cara saya mengurutkan berdasarkan nilai" - dan saya pikir posting asli sedang mencoba untuk mengatasi masalah seperti itu. Dan solusinya adalah melakukan semacam daftar kunci, berdasarkan nilai-nilai, seperti yang ditunjukkan di atas.


31
Ini juga baik tetapi key=operator.itemgetter(1)harus lebih scalable untuk efisiensi daripadakey=d.get
smci

3
@raylu Saya mengamati perilaku "tidak berfungsi" menggunakan 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 Hasilnya berubah setiap kali saya menjalankan kode: aneh . (maaf, tidak bisa menampilkan kode dengan benar)
bli

12
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True)dan for key, val in sorted_keys: print "%s: %d" % (key, val)- itemgetter membuat fungsi ketika dipanggil, Anda tidak menggunakannya secara langsung seperti pada contoh Anda. Dan iterasi polos pada dikt menggunakan kunci tanpa nilai
Izkata

18
saya datang dari masa depan untuk memberi tahu Anda collections.Counter, yang memiliki most_commonmetode yang mungkin menarik bagi Anda :)
Eevee

2
@Eevee - ada itu, risiko disalahpahami dalam komentar singkat non-f2f. Berita gembira Amuzing: collections.Counterditambahkan pada 2,7, yang dirilis hampir tepat 7 tahun yang lalu! (Saya tidak tahu tentang itu saat itu - plus saya akan menghindarinya dalam kode-golf untuk tujuan singkatnya, yang merupakan satu-satunya obsesi permainan)
Nas Banov

859

Anda bisa menggunakan:

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

Ini akan mengurutkan kamus berdasarkan nilai setiap entri dalam kamus dari yang terkecil hingga yang terbesar.

Untuk mengurutkannya dalam urutan menurun, tambahkan saja reverse=True:

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

Memasukkan:

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

Keluaran:

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

Dari apa yang saya lihat ( docs.python.org/2/library/… ), ada kelas yang disebut OrderedDict yang dapat diurutkan dan mempertahankan pesanan sementara masih menjadi kamus. Dari contoh kode, Anda dapat menggunakan lambda untuk mengurutkannya, tetapi saya belum mencobanya secara pribadi: P
UsAndRufus

53
Saya lebih suka key=lambda (k, v): vsecara pribadi
Claudiu

35
@Claudiu Saya suka (k, v)sintaks itu juga, tapi itu tidak tersedia di Python 3 di mana parameter tuple membongkar dihapus.
Bob Stein

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

3
Tidak. Membuat dikte dari daftar tupel yang diurutkan membunuh pesanan lagi ...
Jean-François Fabre

233

Diktik tidak dapat disortir, tetapi Anda dapat membuat daftar diurutkan dari mereka.

Daftar nilai dict yang diurutkan:

sorted(d.values())

Daftar pasangan (kunci, nilai), diurutkan berdasarkan nilai:

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

Urutan apakah kunci dengan nilai yang sama ditempatkan? Saya mengurutkan daftar berdasarkan kunci terlebih dahulu, kemudian berdasarkan nilai, tetapi urutan kunci dengan nilai yang sama tidak tetap.
SabreWolfy

1
Diktik sekarang dapat diurutkan, dimulai dengan CPython 3.6 dan semua implementasi Python lainnya dimulai dengan 3.7
Boris

161

Dalam Python 2.7 baru-baru ini, kami memiliki tipe OrderedDict baru , yang mengingat urutan item ditambahkan.

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

Untuk membuat kamus berurutan baru dari yang asli, urutkan berdasarkan nilainya:

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

The OrderedDict berperilaku seperti dict normal:

>>> 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
Ini bukan pertanyaannya - ini bukan tentang menjaga urutan kunci tetapi tentang "pengurutan berdasarkan nilai"
Nas Banov

10
@Nas Banov: BUKAN menyortir berdasarkan kuncinya. itu menyortir dalam urutan, kami membuat item. dalam kasus kami, kami urutkan berdasarkan nilainya. Sayangnya, 3-item dict sayangnya dipilih sehingga urutannya sama, ketika diurutkan berdasarkan nilai dan kunci, jadi saya memperluas dict sampel.
mykhal

sorted(d.items(), key=lambda x: x[1])Bisakah Anda menjelaskan apa xartinya, mengapa itu bisa x[1]sampai ke lambda? Kenapa tidak bisa x[0]? Terima kasih banyak!
JZAU

1
@Boern d.items()mengembalikan wadah (key, value)tupel seperti daftar . [0]mengakses elemen pertama dari tuple - kunci - dan [1]mengakses elemen kedua - nilainya.
BallpointBen

2
Catatan: Pada 3.6 (sebagai detail implementasi CPython / PyPy) dan pada 3.7 (sebagai jaminan bahasa Python), plain dictadalah penyisipan yang dipesan juga, jadi Anda bisa mengganti OrderedDictdengan dictuntuk kode yang berjalan pada Python modern. OrderedDicttidak benar-benar diperlukan lagi kecuali Anda perlu mengatur ulang urutan yang ada dict(dengan move_to_end/ popitem) atau membutuhkan perbandingan kesetaraan agar peka terhadap pesanan. Ini menggunakan lebih banyak memori daripada yang biasa dict, jadi jika Anda bisa, dictadalah cara untuk pergi.
ShadowRanger

104

UPDATE: 5 DESEMBER 2015 menggunakan Python 3.5

Sementara saya menemukan jawaban yang diterima bermanfaat, saya juga terkejut bahwa itu belum diperbarui untuk merujuk OrderedDict dari modul koleksi perpustakaan standar sebagai alternatif yang layak, modern - dirancang untuk memecahkan jenis masalah yang tepat.

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

Dokumentasi resmi OrderedDict menawarkan contoh yang sangat mirip juga, tetapi menggunakan lambda untuk fungsi sortir:

# 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

Hampir sama dengan jawaban Hank Gay :

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

Atau sedikit dioptimalkan seperti yang disarankan oleh John Fouhy:

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

9
..dan seperti dengan jawaban Hank Gay, Anda tidak perlu tanda kurung. diurutkan () dengan senang hati akan mengambil iterable, seperti ekspresi generator.
John Fouhy

Anda mungkin masih perlu menukar elemen tuple (nilai, kunci) agar berakhir dengan (kunci, nilai). Pemahaman daftar lain diperlukan. [(key, value) for (value, key) in sorted_list_of_tuples]
saidimu apale

tidak, lebih baik meninggalkan tanda kurung siku, karena sortedharus membuat ulang daftar, dan membangun kembali dari gencomp akan lebih cepat. Baik untuk codegolfing, buruk untuk kecepatan. Pertahankan ([])versi jelek .
Jean-François Fabre

75

Seringkali bisa sangat berguna untuk menggunakan namesuple . Misalnya, Anda memiliki kamus 'nama' sebagai kunci dan 'skor' sebagai nilai dan Anda ingin menyortir 'skor':

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

pengurutan dengan skor terendah terlebih dahulu:

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

pengurutan dengan skor tertinggi pertama:

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

Sekarang Anda bisa mendapatkan nama dan skor, katakanlah pemain terbaik kedua (indeks = 1) dengan sangat Pythonically seperti ini:

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

Bagaimana saya bisa mengubahnya kembali ke kamus?
rowana

as_list = [Pemain (v, k) untuk (k, v) di d.items ()] as_dict = dict ((p.name, p.score) untuk p di as_list)
Remi

72

Pada Python 3.6 , built-in dict akan dipesan

Kabar baik, sehingga kasus penggunaan asli OP pasangan pemetaan diambil dari database dengan id string unik sebagai kunci dan nilai numerik sebagai nilai ke dalam dict Python v3.6 + built-in, sekarang harus menghormati urutan memasukkan.

Jika mengatakan dua ekspresi tabel kolom yang dihasilkan dari permintaan database seperti:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

akan disimpan dalam dua Python tuple, k_seq dan v_seq (disejajarkan dengan indeks numerik dan dengan panjang yang sama tentu saja), kemudian:

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

Izinkan untuk keluaran nanti sebagai:

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

menghasilkan dalam hal ini (untuk Python 3.6+ built-in dict baru!):

foo 0
bar 1
baz 42

dalam pemesanan yang sama per nilai v.

Di mana di Python 3.5 instal di mesin saya saat ini menghasilkan:

bar 1
foo 0
baz 42

Detail:

Seperti yang diusulkan pada 2012 oleh Raymond Hettinger (lih. Mail pada python-dev dengan subjek "Kamus yang lebih ringkas dengan iterasi yang lebih cepat" ) dan sekarang (pada 2016) diumumkan dalam email oleh Victor Stinner kepada python-dev dengan subjek "Python 3.6 dict menjadi kompak dan mendapatkan versi pribadi, dan kata kunci menjadi dipesan " karena perbaikan / implementasi masalah 27350 " Compact dan dipesan dict " di Python 3.6 sekarang kita akan dapat, untuk menggunakan dict built-in untuk mempertahankan urutan memasukkan !!

Semoga ini akan mengarah pada implementasi OrderedDict lapisan tipis sebagai langkah pertama. Seperti yang ditunjukkan @ JimFasarakis-Hilliard, beberapa melihat kasus penggunaan untuk tipe OrderedDict juga di masa mendatang. Saya pikir komunitas Python pada umumnya akan memeriksa dengan seksama, apakah ini akan bertahan dalam ujian waktu, dan apa langkah selanjutnya.

Saatnya memikirkan kembali kebiasaan pengkodean kita untuk tidak melewatkan kemungkinan yang dibuka oleh pemesanan stabil:

  • Argumen kata kunci dan
  • (menengah) penyimpanan dict

Yang pertama karena memudahkan pengiriman dalam implementasi fungsi dan metode dalam beberapa kasus.

Yang kedua karena mendorong untuk lebih mudah menggunakan dicts sebagai penyimpanan perantara dalam pemrosesan pipa.

Raymond Hettinger dengan baik hati memberikan dokumentasi yang menjelaskan " The Tech Behind Python 3.6 Dictionaries " - dari presentasi San Francisco Python Meetup Group 2016-DEC-08.

Dan mungkin beberapa Stack Overflow halaman pertanyaan dan jawaban yang dihiasi dengan tinggi akan menerima varian informasi ini dan banyak jawaban berkualitas tinggi akan memerlukan pembaruan per versi juga.

Caveat Emptor (tetapi juga lihat pembaruan di bawah 2017-12-15):

Seperti yang dicatat @ajcr dengan benar: "Aspek pelestarian pesanan dari implementasi baru ini dianggap sebagai detail implementasi dan tidak boleh diandalkan." (dari whatsnew36 ) bukan nit picking, tapi kutipannya terpotong agak pesimistis ;-). Ini berlanjut sebagai "(ini dapat berubah di masa depan, tetapi diinginkan untuk memiliki implementasi dict baru ini dalam bahasa untuk beberapa rilis sebelum mengubah spesifikasi bahasa untuk mandat semantik pelestarian pesanan untuk semua implementasi Python saat ini dan 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). "

Jadi seperti dalam beberapa bahasa manusia (misalnya Jerman), penggunaan membentuk bahasa, dan kehendak sekarang telah dinyatakan ... di whatsnew36 .

Pembaruan 2017-12-15:

Dalam surel ke daftar python-dev , Guido van Rossum menyatakan:

Jadikan begitu. "Dict menjaga urutan penyisipan" adalah putusannya. Terima kasih!

Jadi, efek samping versi 3,6 CPython dari pemesanan penyisipan dict sekarang menjadi bagian dari spesifikasi bahasa (dan tidak lagi hanya detail implementasi). Utas surat itu juga memunculkan beberapa tujuan desain yang berbeda untuk collections.OrderedDictdiingatkan oleh Raymond Hettinger selama diskusi.


15
Peringatan pada halaman 'whatsnew' yang Anda tautkan harus ditekankan: aspek pelestarian pesanan dari implementasi baru ini dianggap sebagai detail implementasi dan tidak boleh diandalkan . Tidak seorang pun boleh berasumsi bahwa dicttipe tersebut akan mematuhi urutan penyisipan dalam kode mereka. Ini bukan bagian dari definisi bahasa dan implementasinya dapat berubah pada rilis mendatang. Terus gunakan OrderedDictuntuk menjamin pesanan.
Alex Riley

@ajcr terima kasih atas peringatannya, sangat dihargai - karena smiley dan mungkin sudah terjalin ke dalam tanggapan saya, ini seharusnya menunjukkan, perubahannya sangat besar tetapi tentu saja, hanya tersedia untuk CPython (implementasi referensi) dan PyPy. Untuk sesuatu yang sama sekali berbeda ... Saya jarang berbicara dengan detail non-implementasi ketika mengkode instruksi man-machine. Kalau saja itu Jython ;-) ... Saya mungkin tidak memiliki keberanian untuk menulisnya.
Dilettant

OrderedDictpasti tidak akan jatuh; sebagai gantinya, itu akan menjadi pembungkus tipis di sekitar implementasi dikt saat ini (sehingga Anda dapat menambahkan bahwa itu akan menjadi lebih kompak juga). Menambahkan potongan itu dengan ImportErroride yang tidak tepat karena itu menyesatkan pembaca yang OrderedDicttidak menggunakan.
Dimitris Fasarakis Hilliard

@ JimFasarakis-Hilliard terima kasih atas umpan baliknya. "Gagasan terbaik" membuat saya tersenyum - masa depan sering kali sulit diprediksi. Tapi saya suka saran Anda akan memeriksa sumber, coba dan perbarui jawabannya. Terima kasih lagi.
Dilettant

8
@AlexRiley Peringatan ini tidak lagi akurat. Python3.7 menjamin kamus yang dipesan.
gerrit

42

Saya memiliki masalah yang sama, dan saya menyelesaikannya seperti ini:

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

(Orang yang menjawab "Tidak mungkin untuk menyortir dict" tidak membaca pertanyaan! Bahkan, "Saya dapat mengurutkan pada kunci, tetapi bagaimana saya bisa mengurutkan berdasarkan nilai-nilai?" Jelas berarti bahwa ia menginginkan daftar kunci diurutkan sesuai dengan nilai nilainya.)

Harap perhatikan bahwa pesanan tidak didefinisikan dengan baik (kunci dengan nilai yang sama akan berada dalam urutan acak dalam daftar keluaran).


1
Anda melewatkan nilai dari hasilnya
Dejell

Perhatikan bahwa Anda berdua meng iterasi kamus dan mengambil nilai dengan kunci mereka, jadi kinerja bijaksana ini bukan solusi yang optimal.
Ron Klein

1
@ Debell: sebagai kontributor mengatakan, ia menafsirkan pertanyaan sebagai "bisakah saya mendapatkan daftar kunci diurutkan sesuai dengan nilai". Kami tidak membutuhkan nilai dalam hasilnya, kami memilikinya di kamus.
Maks

36

Jika nilainya numerik, Anda juga dapat menggunakan Counterdari koleksi .

from collections import Counter

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

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

bagaimana jika kamus Anda >>> x = {'hello': 1, 'python': 5, 'world': 300}
James Sapam

@yopy Counter({'hello':1, 'python':5, 'world':300}).most_common()memberi [('world', 300), ('python', 5), ('hello', 1)]. Ini sebenarnya bekerja untuk semua tipe nilai yang dapat diurutkan (walaupun banyak operasi Counter lainnya memang membutuhkan nilai yang dapat dibandingkan dengan int).
lvc

34

Dalam Python 2.7, cukup lakukan:

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

salin-tempel dari: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Nikmati ;-)


25

Ini kodenya:

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

Inilah hasilnya:

Asli

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

Pangkat

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

Coba pendekatan berikut. Mari kita mendefinisikan kamus yang disebut mydict dengan data berikut:

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

Jika seseorang ingin mengurutkan kamus dengan kunci, orang dapat melakukan sesuatu seperti:

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

Ini akan menghasilkan output berikut:

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

Di sisi lain, jika seseorang ingin mengurutkan kamus berdasarkan nilai (seperti yang ditanyakan dalam pertanyaan), seseorang dapat melakukan hal berikut:

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

Hasil dari perintah ini (mengurutkan kamus berdasarkan nilai) harus mengembalikan yang berikut:

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

Luar biasa! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]):memungkinkan Anda untuk mengurutkan berdasarkan subkunci
Andomar

itu memberi saya kesalahan sintaks dekat lambda di Python3
Suleman Elahi

21

Mulai dari Python 3.6, dictobjek sekarang dipesan dengan urutan penyisipan. Ini secara resmi dalam spesifikasi 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}

Sebelum itu, Anda harus menggunakannya OrderedDict.

Dokumentasi Python 3.7 mengatakan:

Diubah dalam versi 3.7: Urutan kamus dijamin menjadi urutan penyisipan. Perilaku ini adalah detail implementasi CPython dari 3.6.


bekerja hebat! dict(sorted(words.items(), key=lambda x: x[1], reverse=True))untuk DESC
vizyourdata

20

Anda dapat membuat "indeks terbalik" juga

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

Sekarang kebalikan Anda memiliki nilai; setiap nilai memiliki daftar kunci yang berlaku.

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

19

Anda dapat menggunakan collections.Counter . Catatan, ini akan berfungsi untuk nilai numerik dan non-numerik.

>>> 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
Bagaimana ini berbeda dari jawaban Ivan Sas ?
Peter Mortensen

15

Anda dapat menggunakan skip dict yang merupakan kamus yang secara permanen diurutkan berdasarkan nilai.

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

Jika Anda menggunakan keys(), values()atau items()Anda akan mengulanginya dalam urutan berdasarkan nilai.

Diimplementasikan menggunakan datastructure daftar skip .


bisakah kita mengubah urutan penyortiran, saat ini, sedang naik, tetapi saya ingin menurun.
Suleman Elahi

afaik Anda harus meniadakan nilai-nilai Anda untuk membalikkan pemesanan
malthe

wow, saya tidak berpikir seperti itu ... terima kasih.
Suleman Elahi

14

Anda juga dapat menggunakan fungsi kustom yang dapat diteruskan ke tombol.

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
pertanyaannya adalah: urutkan berdasarkan nilai, bukan dengan kunci ... Saya suka melihat fungsi. Anda dapat mengimpor koleksi dan tentu saja menggunakan sortir (data.values ​​())
Remi

10

Seperti yang ditunjukkan oleh Dilettant , Python 3.6 sekarang akan menyimpan pesanan ! Saya pikir saya akan berbagi fungsi yang saya tulis yang memudahkan penyortiran iterable (tuple, list, dict). Dalam kasus yang terakhir, Anda bisa mengurutkan baik pada kunci atau nilai, dan itu bisa memperhitungkan perbandingan numerik. Hanya untuk> = 3,6!

Ketika Anda mencoba menggunakan diurutkan pada iterable yang memegang mis string dan ints, diurutkan () akan gagal. Tentu saja Anda dapat memaksa perbandingan string dengan str (). Namun, dalam beberapa kasus Anda ingin melakukan perbandingan numerik aktual di mana 12lebih kecil dari 20(yang tidak terjadi dalam perbandingan string). Jadi saya datang dengan yang berikut ini. Saat Anda ingin perbandingan angka eksplisit, Anda dapat menggunakan flag num_as_numyang akan mencoba melakukan penyortiran angka eksplisit dengan mencoba mengonversi semua nilai menjadi float. Jika itu berhasil, itu akan melakukan pengurutan numerik, jika tidak akan menggunakan perbandingan string.

Komentar untuk perbaikan atau permintaan push disambut.

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

Berikut ini solusi menggunakan zip on d.values()dand.keys() . Beberapa baris di bawah tautan ini (pada objek tampilan Kamus) adalah:

Ini memungkinkan pembuatan pasangan (nilai, kunci) menggunakan zip (): pairs = zip (d.values ​​(), d.keys ()).

Jadi kita bisa melakukan hal berikut:

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

Tentu saja, ingat, Anda perlu menggunakan OrderedDictkarena kamus Python biasa tidak menjaga urutan aslinya.

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

Jika Anda tidak memiliki Python 2.7 atau lebih tinggi, hal terbaik yang dapat Anda lakukan adalah mengulangi nilai-nilai dalam fungsi generator. (Ada OrderedDictuntuk 2.4 dan 2.6 di sini , tetapi

a) Saya tidak tahu seberapa baik kerjanya

dan

b) Anda harus mengunduh dan menginstalnya tentu saja. Jika Anda tidak memiliki akses administratif, maka saya takut pilihannya keluar.)


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

Anda juga dapat mencetak setiap nilai

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

Harap ingat untuk menghapus tanda kurung setelah dicetak jika tidak menggunakan Python 3.0 atau lebih tinggi


kamus Python biasa tidak menjaga urutan asli - seperti Python 3.7, mereka melakukannya.
gerrit

7

Gunakan ValueSortedDict dari 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

Ini berfungsi di 3.1.x:

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

6

Baru belajar keterampilan yang relevan dari Python untuk Semua Orang .

Anda dapat menggunakan daftar sementara untuk membantu Anda mengurutkan kamus:

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

Jika Anda ingin mengurutkan daftar dalam urutan menurun, cukup ubah baris pengurutan asli ke:

tmp = sorted(tmp, reverse=True)

Menggunakan pemahaman daftar, liner satu akan menjadi:

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

Output sampel:

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

ini mengurutkan berdasarkan kunci, bukan oleh nilai.
Rubel

Jika Anda ingin mencetaknya dalam format awal yang harus Anda lakukan: cetak ([(k, v) untuk v, k diurutkan ([(v, k) untuk k, v dalam d.items ()])]))). Outputnya adalah: [('oranye', 1.0), ('apel', 500.1), ('nanas', 789.0), ('pisang', 1500.2)]. Dengan [(k, v) untuk v, k diurutkan ([(v, k) untuk k, v dalam d.items ()], mundur = True)] hasilnya adalah: [('pisang', 1500.2), ('nanas', 789.0), ('apel', 500.1), ('oranye', 1.0)]
Hermes Morales

5

Iterasi melalui dict dan urutkan berdasarkan nilainya dalam urutan menurun:

$ 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

Jika nilai-nilai Anda adalah bilangan bulat, dan Anda menggunakan Python 2.7 atau yang lebih baru, Anda dapat menggunakan collections.Counterbukan dict. The most_commonMetode akan memberikan semua item, diurutkan berdasarkan nilai.


5

Demi kelengkapan, saya memposting solusi menggunakan heapq . Catatan, metode ini akan bekerja untuk nilai numerik dan non-numerik

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

Karena persyaratan untuk mempertahankan kompatibilitas dengan versi Python yang lebih lama saya pikir solusi OrderedDict sangat tidak bijaksana. Anda menginginkan sesuatu yang berfungsi dengan Python 2.7 dan versi yang lebih lama.

Tetapi solusi koleksi yang disebutkan dalam jawaban lain benar-benar hebat, karena Anda melatih kembali hubungan antara kunci dan nilai yang dalam kasus kamus sangat penting.

Saya tidak setuju dengan pilihan nomor satu yang disajikan dalam jawaban lain, karena itu membuang kunci.

Saya menggunakan solusi yang disebutkan di atas (kode yang ditunjukkan di bawah) dan mempertahankan akses ke kedua kunci dan nilai-nilai dan dalam kasus saya pemesanan adalah pada nilai-nilai, tetapi yang penting adalah urutan kunci setelah memesan nilai-nilai.

from collections import Counter

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


>> [('python', 5), ('world', 3), ('hello', 1)]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.