Dictionary

Operasi CRUD pada dictionary, aturan kuncinya, dan iterasi atas keys, values, dan items.

Daftar isi

Dictionary adalah struktur data yang memetakan setiap kunci (key) ke sebuah nilai (value), sehingga pencarian nilai dilakukan melalui kunci dan bukan melalui posisi angka. Struktur ini bersifat mutable, dan kecepatan pencariannya menjadikannya pilihan utama untuk data berpasangan seperti kamus istilah, konfigurasi, dan rekapitulasi. Topik ini membahas operasi CRUD pada dictionary, aturan yang mengikat kuncinya, serta cara iterasi atas kunci, nilai, dan pasangan keduanya.

Membuat dan membaca dictionary#

Literal dictionary ditulis dengan tanda kurung kurawal, pasangan kunci dan nilai dipisahkan tanda titik dua, dan antarpasangan dipisahkan tanda koma. Pembacaan nilai dilakukan dengan menuliskan kuncinya di dalam tanda kurung siku. Apabila kunci tidak ada, error KeyError muncul, sedangkan metode get() mengembalikan None atau nilai cadangan yang diberikan tanpa menimbulkan error.

python Contoh: membuat dan membaca dictionary
stok = {"pensil": 24, "buku": 10, "penghapus": 7}
print(stok["buku"])
print(len(stok))
try:
    print(stok["penggaris"])
except KeyError as e:
    print(type(e).__name__, str(e))
print(stok.get("penggaris"))
print(stok.get("penggaris", 0))
text Keluaran
10
3
KeyError 'penggaris'
None
0

Kunci "penggaris" tidak pernah ditambahkan, sehingga akses langsungnya gagal dengan KeyError. Metode get() menangani situasi yang sama secara berbeda, yaitu mengembalikan None secara default atau mengembalikan 0 karena nilai cadangan 0 diberikan. Pola get() dengan nilai cadangan sering digunakan pada penghitungan agregat.

Dictionary kosong ditulis {}, dan dictionary dapat pula dibangun dari daftar pasangan menggunakan dict([("a", 1), ("b", 2)]). Nilai boleh bertipe apa pun, sedangkan kuncinya wajib memenuhi aturan hashable yang dijelaskan pada bagian berikut. Pada satu dictionary, kunci berupa string dan kunci berupa bilangan dapat digunakan bersama, meskipun kunci dengan tipe yang seragam lebih mudah diperiksa.

Menambah, mengubah, dan menghapus#

Satu bentuk penugasan mengurus dua kebutuhan sekaligus. Penugasan pada kunci yang belum ada menambah pasangan baru, sedangkan penugasan pada kunci yang sudah ada mengganti nilainya. Metode update() menggabungkan isi dictionary lain sekaligus, metode pop() menghapus sebuah kunci dan mengembalikan nilainya, pernyataan del menghapus tanpa mengembalikan apa pun, dan metode setdefault() menambahkan kunci bila belum ada sambil tetap mengembalikan nilai yang berlaku.

python Contoh: CRUD pada dictionary
stok = {"pensil": 24, "buku": 10}
stok["penghapus"] = 7    # kunci baru: menambah
stok["buku"] = 12        # kunci lama: mengubah
print(stok)
stok.update({"pensil": 20, "spidol": 5})
print(stok)
terjual = stok.pop("penghapus")
print(terjual)
del stok["spidol"]
print(stok)
stok.setdefault("spidol", 0)   # kunci ditambah kembali dengan nilai 0
print(stok)
text Keluaran
{'pensil': 24, 'buku': 12, 'penghapus': 7}
{'pensil': 20, 'buku': 12, 'penghapus': 7, 'spidol': 5}
7
{'pensil': 20, 'buku': 12}
{'pensil': 20, 'buku': 12, 'spidol': 0}

Keluaran mengikuti setiap langkahnya. Metode update() mengganti pensil menjadi 20 sekaligus menambah spidol, pop() mengembalikan nilai 7 milik penghapus, dan del menghapus spidol. Pemanggilan setdefault() kemudian menambahkan kembali spidol dengan nilai 0 karena kunci itu saat itu memang tidak ada.

Nilai pada dictionary boleh berupa dictionary lain, sehingga rekapitulasi berlapis dapat dibentuk, misalnya {"Ali": {"tugas": 90, "ujian": 85}}. Pembacaannya dirangkai, yaitu rekap["Ali"]["tugas"] menunjuk nilai tugas milik Ali. Struktur berlapis semacam ini lazim pada data konfigurasi maupun berkas JSON, dan aturan mutasinya tetap sama pada setiap lapisannya.

Aturan kunci dictionary#

Kunci dictionary wajib bersifat hashable, yaitu memiliki nilai hash yang tetap sepanjang hidupnya. String, bilangan, dan tuple memenuhi syarat tersebut, sedangkan list dan dictionary sendiri tidak, karena isinya dapat berubah. Aturan ini bersumber dari cara kerja internalnya, yaitu tabel hash yang menempatkan setiap pasangan berdasarkan nilai hash kuncinya, sehingga pencarian rata-rata selesai dalam waktu O(1)O(1). Kunci yang ditulis dua kali pada satu literal tidak menimbulkan error, melainkan hanya menyisakan nilai yang terakhir.

python Contoh: aturan kunci
coba = {"kunci": 1, "kunci": 2}
print(coba)
posisi = {(1, 2): "titik A"}
print(posisi[(1, 2)])
try:
    d = {["salah"]: 1}
except TypeError as e:
    print(type(e).__name__, str(e))
text Keluaran
{'kunci': 2}
titik A
TypeError unhashable type: 'list'

Kunci "kunci" yang ditulis dua kali menyisakan nilai 2. Tuple (1, 2) sah sebagai kunci sehingga posisi menyimpan titik koordinat dengan baik, sedangkan list ["salah"] ditolak dengan pesan unhashable type. Pada kasus nyata, tuple bersifat hashable selama isinya juga tidak berubah, sehingga kombinasi string dan bilangan biasanya aman.

Satu perilaku yang jarang diduga adalah kesetaraan bilangan lintas tipe. Bilangan 1 dan 1.0 bernilai sama pada Python, sehingga keduanya dianggap kunci yang sama persis oleh dictionary.

python Contoh: 1 dan 1.0 sebagai kunci yang sama
angka = {1: "satu", 1.0: "satu koma nol"}
print(angka)
text Keluaran
{1: 'satu koma nol'}

Kunci yang tersimpan tetap berupa 1 yang pertama, sedangkan nilainya digantikan oleh penugasan terakhir karena keduanya dianggap satu kunci. Aturan praktisnya, gunakan kunci yang tipenya seragam agar perilaku ini tidak menjadi sumber kebingungan.

Iterasi atas kunci, nilai, dan pasangan#

Perulangan for yang menelusuri dictionary secara default menyediakan kuncinya satu per satu. Metode values() menyediakan sisi nilai, sedangkan metode items() menyediakan pasangan kunci dan nilai yang dapat di-unpacking langsung pada kepala perulangan. Operator in menguji keanggotaan kunci. Sejak Python 3.7, urutan penyisipan dijaga dengan pasti, sehingga keluaran iterasi stabil dan mudah direproduksi ulang.

python Contoh: iterasi atas dictionary
nilai_ujian = {"Ali": 88, "Budi": 75, "Citra": 92}
for nama in nilai_ujian:
    print(nama)
total = sum(nilai_ujian.values())
print(total)
for nama, nilai in nilai_ujian.items():
    print(nama, nilai)
text Keluaran
Ali
Budi
Citra
255
Ali 88
Budi 75
Citra 92

Perulangan pertama mencetak tiga kunci sesuai urutan penyisipannya. Fungsi sum() menambahkan seluruh nilai, yaitu 88, 75, dan 92, dengan hasil 255. Perulangan kedua memperlihatkan unpacking nama, nilai pada kepala perulangan, pola yang paling sering dibutuhkan ketika kedua sisi sama-sama diperlukan.

Apabila keluaran perlu terurut menurut abjad, kuncinya diurutkan dahulu dengan for nama in sorted(nilai_ujian), sehingga cetakannya tetap dapat direproduksi. Pengujian in juga sering digunakan sebelum akses, misalnya if "Dewi" in nilai_ujian, karena mengembalikan False tanpa menimbulkan KeyError. Kombinasi keduanya membentuk pola pembacaan yang aman untuk data yang isinya belum pasti.

Kesalahan umum#

Kesalahan pertama adalah mengubah ukuran dictionary saat perulangan for sedang menelusurinya. Python mendeteksi perubahan ukuran tersebut dan menghentikannya dengan error RuntimeError.

python Contoh: menghapus kunci saat iterasi
data = {"a": 1, "b": 2, "c": 3}
try:
    for k in data:
        data.pop(k)
except RuntimeError as e:
    print(type(e).__name__, str(e))
text Keluaran
RuntimeError dictionary changed size during iteration

Perbaikannya adalah menelusuri salinan daftar kuncinya, misalnya for k in list(data), sehingga penghapusan tidak menyentuh objek yang sedang diperulangkan. Pola lain yang setara adalah membangun dictionary baru yang hanya memuat kunci yang ingin dipertahankan.

Kesalahan kedua adalah menganggap hasil get() selalu siap dihitung. Apabila kunci tidak ada dan nilai cadangan tidak diberikan, hasilnya None, dan operasi aritmetika atas None pasti gagal.

python Contoh: aritmetika atas hasil get()
stok = {"pensil": 24, "buku": 10}
jumlah = stok.get("penggaris")
try:
    print(jumlah + 1)
except TypeError as e:
    print(type(e).__name__, str(e))
text Keluaran
TypeError unsupported operand type(s) for +: 'NoneType' and 'int'

Nilai cadangan pada stok.get("penggaris", 0) mencegah situasi ini sejak awal. Apabila None justru diinginkan sebagai penanda ketiadaan, periksa dahulu dengan if jumlah is None sebelum nilainya dihitung.

Kesalahan ketiga adalah menyangka operator in menguji nilai, padahal yang diujinya kunci. Ekspresi 10 in stok memeriksa kunci 10 dan bukan mencari nilai 10, sehingga pemeriksaan nilai harus melalui 10 in stok.values(). Pembedaan ini penting karena keduanya sah secara sintaks tanpa menimbulkan error apa pun.

Ringkasan#

  • Dictionary memetakan kunci ke nilai, dengan kunci yang wajib hashable dan tidak boleh ganda pada satu dictionary.
  • Penugasan pada kunci menambah atau mengubah satu pasangan, sedangkan update(), pop(), del, dan setdefault() menutup sisa kebutuhan CRUD.
  • Iterasi menyasar kunci secara default, sedangkan values() dan items() menyediakan nilai serta pasangan kunci-nilai.
  • Urutan penyisipan dijaga sejak Python 3.7, sehingga keluaran iterasi stabil dan mudah direproduksi.

Referensi#