Pendalaman itertools

Modul itertools untuk islice, chain, groupby, combinations, dan count.

Daftar isi

Modul itertools adalah kumpulan fungsi pustaka standar yang membangun iterator dari iterable lain, semuanya ditulis dalam C dan semuanya hemat memori karena mengalirkan elemen satu per satu. Fungsi-fungsinya menjadi bahan penyusun untuk kebutuhan yang lebih spesifik daripada zip dan enumerate, mulai dari memotong stream tak terbatas, menyambung beberapa sumber, mengelompokkan data, sampai menyusun pasangan. Topik ini membahas count, islice, chain, groupby, dan combinations beserta kebiasaan pemakaiannya.

count dan islice: stream tak terbatas berjendela#

Fungsi count(start, step) menghasilkan angka berkelanjutan tanpa akhir, sehingga perannya seperti range yang tidak pernah selesai. Karena perulangan dan fungsi konsumsi menuntut sumber yang berhenti, fungsi islice(iterator, awal, akhir, langkah) memotong iterator apa pun menjadi jendela tertentu dan berhenti persis pada batasnya. Dua fungsi ini hampir selalu tampil bersama, yaitu count sebagai sumber dan islice sebagai pembatasnya.

python Contoh: count yang dipotong islice
from itertools import count, islice

print(list(islice(count(10, 5), 4)))
print(list(islice(count(), 3, 8, 2)))
text Keluaran
[10, 15, 20, 25]
[3, 5, 7]

Pemanggilan pertama mengambil empat angka berurutan dengan selisih lima, sedangkan yang kedua memotong mulai indeks 3 sampai sebelum 8 dengan langkah dua. islice juga bekerja atas iterator biasa tanpa menggandakan datanya, sebagaimana contoh berikut atas list kuadrat, dan hasilnya tetap berupa iterator yang dikonsumsi lewat list() untuk diperiksa.

python Contoh: islice pada list kuadrat
from itertools import islice

data = [n * n for n in range(10)]
print(list(islice(data, 2, 7, 2)))
text Keluaran
[4, 16, 36]

Hasilnya elemen pada indeks 2, 4, dan 6, dan tidak ada list baru yang dibangun untuk keseluruhan data selain hasilnya. Keunggulan ini nyata ketika jendelanya jauh di tengah stream yang besar, karena islice melewatkan elemen awal tanpa menyalinnya. Batas yang diberikan wajib ada ketika sumbernya tak terbatas, sebab islice hanyalah jendela dan tidak pernah menghentikan sumbernya sendiri.

chain menyambung beberapa urutan#

Fungsi chain(*iterables) mengalirkan elemen dari beberapa iterable secara berurutan seolah-olah semuanya satu urutan tunggal. Alternatif gabungan lewat operator + menuntut kedua sumber berupa list dan menyalin seluruh isinya, sedangkan chain membaca keduanya tanpa menyalin, sehingga aman untuk sumber besar maupun iterator dari generator. Varian chain.from_iterable menerima satu iterable yang isinya beberapa iterable, cocok ketika jumlah sumbernya baru diketahui saat berjalan.

python Contoh: chain dan chain.from_iterable
from itertools import chain

piket_senin = ["Ali", "Budi"]
piket_selasa = ["Citra", "Dewi"]
print(list(chain(piket_senin, piket_selasa)))
print(list(chain.from_iterable([[1, 2], [3], [4, 5]])))
text Keluaran
['Ali', 'Budi', 'Citra', 'Dewi']
[1, 2, 3, 4, 5]

Kedua bentuk menghasilkan urutan tunggal, dan perbedaannya hanya pada cara sumbernya diberikan. Seluruh fungsi modul ini bersifat lazy, sehingga chain membaca sumber-sumbernya hanya sejauh yang dikonsumsi, dan sumber kedua bahkan belum disentuh selama konsumen masih membaca sumber pertama. Hal ini berbeda dari penggabungan list_a + list_b yang menyalin seluruh elemen sebelum satu elemen pun dibaca. Pola yang lazim adalah meratakan baris-baris dari berkas atau daftar bersarang menjadi satu aliran, lalu mengalirkannya ke sum, max, atau perulangan lain tanpa membangun gabungan yang utuh di memori.

groupby mengelompokkan elemen berdampingan#

Fungsi groupby(iterable, key) menghasilkan pasangan berupa nilai kunci dan iterator anggota kelompoknya, tetapi hanya untuk elemen yang berdampingan dan kuncinya sama. Perilaku ini berbeda dari pengelompokan pada dictionary yang menyatukan elemen yang tersebar, sehingga aturan pemakaiannya tegas, yaitu urutkan data dengan kunci yang sama terlebih dahulu agar seluruh anggota satu kelompok benar-benar berdampingan.

python Contoh: groupby setelah data diurutkan
from itertools import groupby

kata = ["apel", "anggur", "jeruk", "kiwi", "kelapa", "mangga"]
urut = sorted(kata, key=lambda k: k[0])
for huruf, kelompok in groupby(urut, key=lambda k: k[0]):
    print(huruf, list(kelompok))
text Keluaran
a ['apel', 'anggur']
j ['jeruk']
k ['kiwi', 'kelapa']
m ['mangga']

Pola pemanfaatannya lazim untuk data yang memang tersusun menurut waktunya, seperti baris log yang dikelompokkan per sesi atau per jam. Nilai kunci yang dihasilkan berasal dari argumen key, sedangkan iterator kelompoknya berisi elemen asli dalam urutan kemunculannya, bukan hasil pengurutan ulang. Apabila kelompok perlu ditampung untuk dipakai lebih dari sekali, kumpulkan setiap kelompok menjadi list pada putaran pertama.

Batas perilakunya terlihat pada data yang belum diurutkan. Kelompok pada data berikut terpecah karena anggota dengan kunci yang sama tidak berdampingan, dan hasilnya berupa tiga kelompok alih-alih dua.

python Contoh: kelompok yang terpecah tanpa pengurutan
from itertools import groupby

for nilai, kelompok in groupby([1, 1, 2, 1, 1]):
    print(nilai, len(list(kelompok)))
text Keluaran
1 2
2 1
1 2

combinations menyusun pasangan#

Fungsi combinations(iterable, r) menghasilkan tuple berisi rr elemen dari sebuah iterable tanpa memperhatikan urutan pilihannya, sedangkan permutations(iterable, r) menganggap urutan pilihan yang berbeda sebagai hasil yang berbeda. Keduanya mengalirkan hasil satu per satu tanpa menyusun seluruh kemungkinan di memori terlebih dahulu, sehingga jumlah kombinasi yang besar tetap dapat diproses per bagian.

python Contoh: combinations dan permutations
from itertools import combinations, permutations

tim = ["Ali", "Budi", "Citra"]
print(list(combinations(tim, 2)))
print(list(permutations(tim, 2)))
text Keluaran
[('Ali', 'Budi'), ('Ali', 'Citra'), ('Budi', 'Citra')]
[('Ali', 'Budi'), ('Ali', 'Citra'), ('Budi', 'Ali'), ('Budi', 'Citra'), ('Citra', 'Ali'), ('Citra', 'Budi')]

Tiga anggota tim menghasilkan tiga pasangan bermain melalui combinations, sedangkan permutations menghasilkan enam urutan karena posisinya diperhitungkan. Kombinasi cocok untuk pasangan permainan, pemilihan sampel, dan gabungan pengaturan yang urutannya tidak membedakan hasil, sedangkan permutasi dipakai ketika susunannya sendiri bermakna. Banyaknya kombinasi mengikuti notasi binomial (nr)\binom{n}{r}, yang tumbuh cepat untuk rr yang besar, sehingga fungsi ini biasa dipakai bersama islice atau perulangan yang berhenti lebih awal ketika seluruh kemungkinannya tidak diperlukan.

Kesalahan umum#

Kesalahan pertama adalah mengiterasi groupby tanpa mengurutkan data terlebih dahulu, dan contoh pemecahannya sudah diperlihatkan pada bagian sebelumnya. Perbaikannya selalu sama, yaitu sorted(data, key=...) dengan kunci yang persis sama dengan kunci groupby, karena dua kunci yang berbeda adalah dua sumber kegagalan yang sulit dilacak.

Kesalahan kedua adalah menganggap iterator itertools sebagai list yang dapat dibaca ulang. Semua fungsi modul ini menghasilkan iterator sekali pakai, sehingga pemakaian kedua menghasilkan urutan kosong tanpa pesan apa pun.

python Contoh: islice yang sudah dikonsumsi
from itertools import count, islice

jendela = islice(count(), 3)
print(list(jendela))
print(list(jendela))
text Keluaran
[0, 1, 2]
[]

Perbaikannya adalah menyimpan hasilnya sebagai list bila data perlu dibaca berkali-kali, atau menyusun ulang rantai iteratornya setiap kali. Kebiasaan yang aman adalah memperlakukan seluruh keluaran modul ini sebagai aliran sekali lewat, lalu memilih list hanya pada titik akhir ketika data benar-benar harus ditampung.

Ringkasan#

  • count menghasilkan stream angka tanpa akhir, dan islice memberi jendela berhenti atas iterator apa pun tanpa menyalin data.
  • chain menyambung beberapa iterable menjadi satu aliran, dengan varian from_iterable untuk sumber yang jumlahnya dinamis.
  • groupby mengelompokkan elemen yang berdampingan menurut kunci, sehingga data wajib diurutkan dengan kunci yang sama terlebih dahulu.
  • combinations dan permutations menyusun pilihan tanpa urutan dan dengan urutan, mengalirkan hasilnya satu per satu.

Referensi#