Soal 1Apa cara paling ringkas untuk mendapatkan count kemunculan per elemen dari list nums dalam satu baris?
collections — Counter / defaultdict / deque / namedtuple
Pelajari Counter untuk hitung kemunculan, defaultdict untuk key hilang, operasi O(1) dua ujung dan ring buffer deque, serta record bernama namedtuple lewat contoh.
Modul collections mengumpulkan struktur data khusus yang mengisi celah yang ditinggalkan oleh list / dict / tuple. Artikel ini membahas empat yang paling sering kamu pakai di proyek nyata: Counter / defaultdict / deque / namedtuple, secara berurutan.
Untuk apa masing-masing dari empat ini
Setiap satu hadir untuk menyederhanakan kasus yang canggung kalau ditulis dengan built-in biasa. Tabel di bawah memberi kamu pandangan menyeluruh, lalu setiap bagian membahas cara memakainya.
list / dict / tuple biasa.| Tipe | Masalah yang diselesaikan | Alternatif biasa |
|---|---|---|
| Counter | Menghitung elemen satu per satu dengan loop terlalu panjang | for + dict tally |
| defaultdict | Perlu if x not in d: d[x] = ... sebelum memakai key baru | dict.setdefault(...) |
| deque | list.insert(0, ...) dan list.pop(0) lambat (O(n)) | list (cukup untuk data kecil) |
| namedtuple | Elemen tuple hanya bisa diakses lewat posisi | dataclass atau dict (lebih berat) |
Counter — hitung kemunculan dalam satu baris
Counter adalah class yang menerima iterable (list, string, dll.) dan mengembalikan dict berisi berapa kali setiap elemen muncul. Dengan dict biasa, kamu harus menulis loop yang memeriksa apakah key sudah ada, menginisialisasinya ke 1 jika belum, atau menambahkannya jika sudah — tetapi Counter menyelesaikan pekerjaan yang sama dalam satu baris: Counter(list).
Nilai kembaliannya adalah subclass dari dict, jadi kamu bisa mengambil nilai dengan counter["apple"] seperti dict biasa. Ada juga .most_common(N), yang mengembalikan list tuple (elemen, count) dalam urutan menurun — pas untuk tampilan ranking.
most_common(N) mengembalikan top N berdasarkan frekuensi, jadi kamu bisa menulis tampilan ranking dalam satu baris.defaultdict — auto-inisialisasi key yang hilang
defaultdict adalah dict yang otomatis menyisipkan nilai default ketika kamu mengakses key yang belum ada. Dengan dict biasa, kamu harus menulis tarian pemeriksaan keberadaan + inisialisasi setiap kali, seperti if key not in d: d[key] = []. Dengan defaultdict, kamu meneruskan fungsi yang menghasilkan nilai awal saat membuatnya, dan ia memanggil fungsi itu otomatis pertama kali key yang hilang disentuh.
Dua pola yang paling sering kamu lihat adalah defaultdict(list) (list kosong untuk key yang hilang) dan defaultdict(int) (0 untuk key yang hilang). Argumennya adalah fungsi yang mengembalikan nilai awal ketika dipanggil tanpa argumen — list dan int keduanya memenuhi (mereka mengembalikan [] dan 0 masing-masing), jadi kamu meneruskannya langsung.
list untuk list kosong, int untuk 0, set untuk set kosong.Kapan memilih Counter vs. defaultdict
Jika kamu hanya ingin menghitung sesuatu, Counter lebih ringkas (dan kamu mendapatkan most_common secara gratis). Jika kamu mengelompokkan ke list atau set — apa pun yang nilai awalnya container kosong — defaultdict(list) / defaultdict(set) lebih cocok.
deque — operasi O(1) di kedua ujung
deque (double-ended queue) adalah struktur data mirip list yang mendukung penambahan dan penghapusan dari kedua ujung. list biasa sudah menangani operasi ujung kanan via append dan pop, tetapi list.insert(0, x) dan list.pop(0) menggeser setiap elemen satu slot di belakang layar, jadi mereka berakhir O(n) (lebih lambat saat list bertambah).
deque dirancang sehingga kedua ujungnya O(1) (waktu konstan terlepas dari panjang), menjadikannya pilihan tepat untuk antrian, buffer histori, dan menyimpan N entri terbaru — di mana pun kamu perlu push dan pop dari kedua sisi. Argumen maxlen sangat berguna: set panjang maksimum, dan penambahan melampaui batas itu diam-diam menjatuhkan elemen di ujung berlawanan, memberi kamu ring buffer secara gratis.
deque(maxlen=N), kamu mendapatkan ring buffer yang otomatis menjatuhkan yang tertua saat penuh.| Method | Efek | Biaya |
|---|---|---|
| append(x) | Tambah ke ujung kanan | O(1) |
| appendleft(x) | Tambah ke ujung kiri | O(1) |
| pop() | Hapus dari ujung kanan | O(1) |
| popleft() | Hapus dari ujung kiri | O(1) |
| maxlen=N | Set panjang maksimum (ring buffer) | Ujung berlawanan dijatuhkan otomatis |
namedtuple — record ringan yang menamai field tuple
namedtuple adalah fungsi yang mendefinisikan tuple bernama dalam satu baris. Tuple biasa seperti (3, 4) hanya bisa diakses lewat posisi (p[0] / p[1]), jadi pembaca harus mengingat slot mana yang mana. namedtuple membiarkan kamu menulis p.x / p.y dengan nama bermakna, yang merupakan kemenangan keterbacaan besar.
Ia juga tetap kompatibel dengan tuple biasa — indexing p[0] dan unpacking *p masih bekerja — jadi kamu bisa menambahkan nama ke kode berbasis tuple yang sudah ada tanpa merusak apa pun. Ini ekstensi ringan.
_asdict() mengonversi ke dict, yang bekerja baik dengan JSON dan pprint.namedtuple vs. dataclass
Jika kamu hanya butuh record ringan immutable, gunakan namedtuple. Jika kamu ingin method, nilai default, dan type hint terperinci, dataclass (dibahas dua artikel lagi) adalah alat yang tepat. Kekuatan namedtuple adalah kompatibilitas tuple — sempurna untuk mengganti tipe kembalian yang sudah ada seperti def f() -> tuple[int, int]: tanpa merusak pemanggil.
tambahan namedtuple — repr / index / _asdict
Di atas akses bernama gaya class, namedtuple memberi kamu akses indeks yang kompatibel dengan tuple, repr yang mudah dibaca, dan method _asdict untuk konversi dict. Kamu akan memakai ini untuk debugging, kompatibilitas dengan API yang sudah ada, dan serialisasi JSON, antara lain.
Cek Pemahaman
Jawab setiap pertanyaan satu per satu.
Soal 2Setelah membuat defaultdict(list), apa yang akses pertama ke key baru d["x"] berikan?
Soal 3Mana yang paling cocok ketika kamu ingin menyimpan hanya 5 item terbaru?