Bagaimana cara menyimpan kunci / nilai dalam urutan yang sama seperti yang dinyatakan?

320

Saya memiliki kamus yang saya nyatakan dalam urutan tertentu dan ingin menyimpannya dalam urutan itu setiap saat. Kunci / nilai tidak dapat disimpan dengan benar berdasarkan nilainya, saya hanya menginginkannya dalam urutan yang saya nyatakan.

Jadi jika saya punya kamus:

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}

Itu tidak dalam urutan itu jika saya melihatnya atau mengulanginya, apakah ada cara untuk memastikan Python akan menjaga urutan eksplisit bahwa saya mendeklarasikan kunci / nilai?

roflwaffle
sumber

Jawaban:

229

Dari Python 3.6 dan seterusnya, standar dict tipe mempertahankan urutan penyisipan secara default.

Mendefinisikan

d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}

akan menghasilkan kamus dengan kunci dalam urutan yang tercantum dalam kode sumber.

Ini dicapai dengan menggunakan array sederhana dengan bilangan bulat untuk tabel hash jarang, di mana bilangan bulat indeks ke array lain yang menyimpan pasangan nilai kunci (ditambah hash yang dihitung). Array yang terakhir hanya terjadi untuk menyimpan item dalam urutan penyisipan, dan seluruh kombinasi sebenarnya menggunakan lebih sedikit memori daripada implementasi yang digunakan dalam Python 3.5 dan sebelumnya. Lihat posting ide asli oleh Raymond Hettinger untuk detailnya.

Dalam 3.6 ini masih dianggap sebagai detail implementasi; lihat dokumentasi What's New in Python 3.6 :

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

Python 3.7 meninggikan detail implementasi ini ke spesifikasi bahasa , jadi sekarang wajib yang dictmenjaga ketertiban di semua implementasi Python yang kompatibel dengan versi itu atau yang lebih baru. Lihat pernyataan oleh BDFL .

Anda mungkin masih ingin menggunakan collections.OrderedDict()kelas dalam kasus-kasus tertentu, karena ia menawarkan beberapa fungsionalitas tambahan di atas dicttipe standar . Seperti menjadi reversibel (ini meluas ke objek tampilan ), dan mendukung pemesanan ulang (melalui move_to_end()metode ).

Martijn Pieters
sumber
Sayangnya ini tidak relevan untuk pembuatan kamus . Kamus yang ditentukan seperti dalam contoh dalam kode tidak dijamin untuk mempertahankan urutan yang sama. Ini berarti Anda harus membuat dict kosong, dan secara manual memasukkan setiap elemen jika Anda ingin mengontrol pesanan.
naught101
8
@ naught101: tidak, ini tidak berlaku untuk penciptaan dict. Dalam Python 3.7 dan lebih tinggi, menggunakan tampilan dict seperti yang ditunjukkan dalam pertanyaan dijamin untuk membuat daftar kunci-kunci itu secara berurutan . Pasangan nilai kunci seperti tertulis dimasukkan dari kiri ke kanan, karena spesifikasi bahasa menjamin bahwa : Jika urutan pasangan kunci / datum yang dipisahkan koma diberikan, mereka dievaluasi dari kiri ke kanan untuk menentukan entri kamus . The dict()dokumentasi bahkan termasuk contoh.
Martijn Pieters
175
from collections import OrderedDict
OrderedDict((word, True) for word in words)

mengandung

OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])

Jika nilainya True(atau objek abadi lainnya), Anda juga dapat menggunakan:

OrderedDict.fromkeys(words, True)
eumiro
sumber
2
Patut dicatat, tentu saja, bahwa bagian yang 'tidak berubah' bukanlah aturan yang keras dan cepat yang akan ditegakkan oleh Python - itu "hanya" ide yang bagus.
lvc
11
Sadarilah bahwa solusi seperti: tidak OrderedDict(FUTURE=[], TODAY=[], PAST=[])akan berhasil, ketika disebutkan pendekatan: OrderedDict([('FUTURE', []), ('TODAY', []), ('PAST', [])])akan menjaga ketertiban.
andilabs
2
@andi Saya punya masalah lain, ketika menggunakan jsonify, OrderedDict tampaknya kehilangan pesanan ketika menghasilkan data json. Bagaimana cara mengatasinya?
tyan
github.com/pallets/flask/issues/974 ini dapat digunakan untuk menyelesaikan masalah ..
tyan
5
Python3.7 sekarang telah dipesan secara default. mail.python.org/pipermail/python-dev/2017-December/151283.html
sertsedat pada
167

Daripada menjelaskan bagian teoretis, saya akan memberikan contoh sederhana.

>>> from collections import OrderedDict
>>> my_dictionary=OrderedDict()
>>> my_dictionary['foo']=3
>>> my_dictionary['aol']=1
>>> my_dictionary
OrderedDict([('foo', 3), ('aol', 1)])
>>> dict(my_dictionary)
{'foo': 3, 'aol': 1}
Mohit Dabas
sumber
16
Apakah ada cara untuk secara massal menetapkan OrderedDict seperti tipe Dict?
tyan
2
OrderedDictmemang memecahkan masalah, tetapi ... dalam contoh khusus ini Anda mendapatkan hasil yang persis sama menggunakan kamus standar
Tonechas
2
@Tonechas: Saya baru saja mencoba contoh dengan kamus standar, dan saya mengerti. {'aol': 1, 'foo': 3}Jadi saya pikir ini adalah contoh ilustrasi yang bagus.
twasbrillig
4
Ada pelajaran untuk semua orang: ditemukan (saya kira sekitar rilis 2.4) bahwa hashing yang dapat diprediksi Python dapat menimbulkan kerentanan keamanan , jadi sekarang tidak ada jaminan bahwa bahkan dua jalan berbeda dari kode yang sama akan memberikan urutan yang sama dalam standar dikt.
holdenweb
1
@tyan Anda dapat memanggil OrderedDict.update()dengan yang berisi pasangan kunci-nilai iterable: d1.upate([(key1, val1), (key2, val2)]).
Ruud Althuizen
37

Perhatikan bahwa jawaban ini berlaku untuk versi python sebelum python3.7. CPython 3.6 mempertahankan urutan penyisipan dalam sebagian besar keadaan sebagai detail implementasi. Mulai dari Python3.7 dan seterusnya, telah dinyatakan bahwa implementasi HARUS mempertahankan urutan penyisipan agar sesuai.


kamus python tidak berurutan. Jika Anda ingin kamus yang dipesan, coba koleksi.OrderedDict .

Perhatikan bahwa OrderedDict diperkenalkan ke perpustakaan standar dengan python 2.7. Jika Anda memiliki versi python yang lebih lama, Anda bisa menemukan resep untuk kamus yang dipesan di ActiveState .

mgilson
sumber
lihat @ martijn di atas. Dari python 3.6 dan seterusnya, dict mendukung pemesanan penyisipan.
tpk
13

Kamus akan menggunakan perintah yang membuat pencarian menjadi efisien, dan Anda tidak dapat mengubahnya,

Anda bisa menggunakan daftar objek (elemen 2 tuple dalam kasus sederhana, atau bahkan kelas), dan menambahkan item ke akhir. Anda kemudian dapat menggunakan pencarian linear untuk menemukan item di dalamnya.

Atau Anda bisa membuat atau menggunakan struktur data yang berbeda yang dibuat dengan tujuan mempertahankan pesanan.

Lancer Api
sumber
Kamus akan menggunakan perintah yang membuat pencarian menjadi efisien Akhirnya, seseorang menunjukkannya.
scharette
7

Saya menemukan posting ini sambil mencoba mencari cara agar OrderedDict berfungsi. PyDev untuk Eclipse tidak dapat menemukan OrderedDict sama sekali, jadi saya akhirnya memutuskan untuk membuat tuple dari nilai-nilai kunci kamus saya karena saya ingin mereka dipesan. Ketika saya perlu menampilkan daftar saya, saya hanya mengulangi nilai-nilai tuple dan menyambungkan 'kunci' iterasi dari tuple ke dalam kamus untuk mengambil nilai-nilai saya dalam urutan yang saya butuhkan.

contoh:

test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
test_tuple = ( 'val1', 'val2', 'val3', 'val4')
for key in test_tuple: print(test_dict[key])

Ini sedikit rumit, tapi aku terdesak waktu dan ini solusinya.

catatan: daftar daftar mendekati yang disarankan orang lain tidak masuk akal bagi saya, karena daftar disusun dan diindeks (dan juga struktur yang berbeda dari kamus).

smushface
sumber
Solusi bagus Saya akan menggunakannya untuk menulis json ke file, selalu dalam urutan yang sama.
Hrvoje T
6

Anda tidak dapat benar-benar melakukan apa yang Anda inginkan dengan kamus. Kamus Anda sudah d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}dibuat. Saya menemukan tidak ada cara untuk menjaga setelah itu sudah dibuat. Apa yang saya lakukan adalah membuat file json sebagai gantinya dengan objek:

{"ac":33,"gw":20,"ap":102,"za":321,"bs":10}

Saya menggunakan:

r = json.load(open('file.json'), object_pairs_hook=OrderedDict)

kemudian digunakan:

print json.dumps(r)

untuk memverifikasi.

nealous3
sumber
1
Jadi mengapa tidak memulai dengan OrderedDict dari daftar? File JSON tidak benar-benar menambahkan apa pun di sini.
Martijn Pieters
Ya, daftar lebih berguna untuk menjaga ketertiban tetapi jawabannya adalah sehubungan dengan pertanyaan tentang pemesanan kamus. Hanya memberi tahu orang-orang tentang keterbatasan menggunakan kamus dan memberi mereka kemungkinan penyelesaian jika mereka perlu menggunakan kamus untuk beberapa alasan.
nealous3
1
Tetapi bagian itu sudah diliputi oleh jawaban yang jauh lebih tua, kembali ke 2012.
Martijn Pieters
3
from collections import OrderedDict
list1 = ['k1', 'k2']
list2 = ['v1', 'v2']
new_ordered_dict = OrderedDict(zip(list1, list2))
print new_ordered_dict
# OrderedDict([('k1', 'v1'), ('k2', 'v2')])
pengguna11502624
sumber
masalah utama yang bukan dict lagi, itu daftar tuple
Oleg
2

Alternatif lain adalah dengan menggunakan Panda dataframekarena menjamin urutan dan lokasi indeks item dalam struktur seperti dict.

Ville
sumber
1

Umumnya, Anda dapat merancang sebuah kelas yang berperilaku seperti kamus, terutama menjadi menerapkan metode __contains__, __getitem__, __delitem__, __setitem__dan beberapa lagi. Kelas itu dapat memiliki perilaku apa pun yang Anda suka, misalnya memberikan iterator yang diurutkan di atas kunci ...

Rasmus Kaj
sumber
1

jika Anda ingin memiliki kamus dalam urutan tertentu, Anda juga dapat membuat daftar daftar, di mana item pertama adalah kuncinya, dan item kedua adalah nilainya dan akan terlihat seperti contoh ini

>>> list =[[1,2],[2,3]]
>>> for i in list:
...     print i[0]
...     print i[1]

1
2
2
3
pelos
sumber
7
Itu bukan "kamus" karena Anda tidak dapat mencari item dengan kunci mereka tanpa mencari melalui seluruh koleksi (mengambil waktu O (n)).
BHSPitMonkey
1
Ya, ini bukan kamus, tetapi, tergantung pada situasinya, itu bisa memberikan solusi yang valid masalah poster asli.
SunSparc
dia tidak mengatakan dengan tepat apa yang kita inginkan, hanya itu ingin dapat memesannya =), seperti biasa ada banyak cara untuk melakukan satu hal.
pelos
1

Saya memiliki masalah serupa ketika mengembangkan proyek Django. Saya tidak bisa menggunakan OrderedDict, karena saya menjalankan versi python lama, jadi solusinya adalah menggunakan kelas SortedDict Django:

https://code.djangoproject.com/wiki/SortedDict

misalnya,

from django.utils.datastructures import SortedDict
d2 = SortedDict()
d2['b'] = 1
d2['a'] = 2
d2['c'] = 3

Catatan: Jawaban ini berasal dari tahun 2011. Jika Anda memiliki akses ke Python versi 2.7 atau lebih tinggi, maka Anda harus memiliki akses ke standar sekarang collections.OrderedDict, yang banyak contohnya telah disediakan oleh orang lain di utas ini.

Evan B.
sumber
0

Anda dapat melakukan hal yang sama yang saya lakukan untuk kamus.

Buat daftar dan kamus kosong:

dictionary_items = {}
fields = [['Name', 'Himanshu Kanojiya'], ['email id', '[email protected]']]
l = fields[0][0]
m = fields[0][1]
n = fields[1][0]
q = fields[1][1]
dictionary_items[l] = m
dictionary_items[n] = q
print dictionary_items
Himanshu Kanojiya
sumber