Set adalah collection yang tidak menerima duplikat. Ketika kita perlu menyimpan nilai unik seperti kode akses, daftar ID pengguna, atau tag artikel, Set adalah pilihan yang tepat. Pada chapter ini kita akan membuat set, memeriksa keanggotaan elemen, dan menerapkan operasi himpunan klasik: union, intersect, dan subtract.
Karakteristik Set #
Set<T> memiliki dua jaminan utama:
- Tidak ada duplikat — pemanggilan
setOf("A", "A", "B")menghasilkan set berisi"A"dan"B"saja. - Tanpa jaminan urutan — implementasi
LinkedHashSetmempertahankan urutan penyisipan, sedangkanHashSettidak.
Pustaka standar Kotlin memilih LinkedHashSet sebagai implementasi default setOf, sehingga urutan penyisipan tetap terjaga. Tetapi kontrak Set sendiri tidak menjamin urutan tertentu, jadi kita perlu berhati-hati saat menulis kode yang bergantung pada urutan.
Membuat Set Read-Only #
val buah: Set<String> = setOf("Apel", "Jeruk", "Pisang")
val angka = setOf(1, 2, 2, 3) // Set<Int>: {1, 2, 3}
val kosong: Set<Int> = emptySet()Karena Set tidak punya indeks, kita tidak bisa menulis set[0]. Untuk memeriksa keanggotaan, gunakan contains(x) atau operator in.
Operasi Himpunan #
Set mendukung operasi himpunan klasik:
| Operasi | Fungsi | Hasil |
|---|---|---|
| Union | a.union(b) | Elemen yang ada di a atau b (atau keduanya) |
| Intersect | a.intersect(b) | Elemen yang ada di a dan b sekaligus |
| Subtract | a.subtract(b) | Elemen yang ada di a tetapi tidak di b |
| Subset | a.containsAll(b) | Apakah semua elemen b ada di a |
union, intersect, dan subtract mengembalikan Set baru; collection asli tidak berubah. Operasi union juga menerima koleksi lain yang bukan Set (misalnya List) karena konsepnya berlaku universal.
Contoh Lengkap #
Berikut program yang memperagakan pembuatan, pemeriksaan, dan operasi himpunan:
fun main() {
val kodeAkses = setOf("A1", "B2", "A1", "C3")
println("Set kode akses: ${kodeAkses.sorted()}")
// Duplikat diabaikan
val buah = setOf("Apel", "Jeruk", "Apel", "Pisang", "Jeruk")
println("Set buah (duplikat hilang): ${buah.sorted()}")
// Ukuran setelah penghapusan duplikat
println("Jumlah buah unik: ${buah.size}")
// contains dan in
println("Apakah \"Pisang\" ada? ${buah.contains("Pisang")}")
println("Apakah \"Mangga\" ada? ${"Mangga" in buah}")
// Operasi himpunan: union, intersect, subtract
val timA = setOf("Budi", "Siti", "Dewi", "Andi")
val timB = setOf("Dewi", "Andi", "Rian", "Putri")
val gabungan = timA.union(timB)
println("Union: ${gabungan.sorted()}")
val irisan = timA.intersect(timB)
println("Intersect: ${irisan.sorted()}")
val selisihA = timA.subtract(timB)
println("A - B: ${selisihA.sorted()}")
val selisihB = timB.subtract(timA)
println("B - A: ${selisihB.sorted()}")
// symmetricDifference (ekstensi stdlib)
val symDiff = timA.filter { it !in timB } + timB.filter { it !in timA }
println("Symmetric difference: ${symDiff.sorted()}")
// Subset dan superset
val kecil = setOf("Budi", "Siti")
println("kecil subsetOf timA? ${kecil.containsAll(timA)}")
println("timA containsAll kecil? ${timA.containsAll(kecil)}")
// Set elemen nullable
val denganNull: Set<String?> = setOf("a", null, "a", "b")
println("Set dengan null (sorted): ${denganNull.toList().sortedBy { it ?: "" }}")
}Output yang Dihasilkan:
Set kode akses: [A1, B2, C3]
Set buah (duplikat hilang): [Apel, Jeruk, Pisang]
Jumlah buah unik: 3
Apakah "Pisang" ada? true
Apakah "Mangga" ada? false
Union: [Andi, Budi, Dewi, Putri, Rian, Siti]
Intersect: [Andi, Dewi]
A - B: [Budi, Siti]
B - A: [Putri, Rian]
Symmetric difference: [Budi, Putri, Rian, Siti]
kecil subsetOf timA? false
timA containsAll kecil? true
Set dengan null (sorted): [null, a, b]Mari kita bedah baris-baris penting di atas:
kodeAkses.sorted():Setdefault menggunakanLinkedHashSetsehingga urutan penyisipan dipertahankan. Memanggilsorted()memastikan output selalu deterministik di berbagai implementasi.buah.size: jumlah elemen unik. Walaupun literalsetOfmenulis"Apel"dua kali, hanya satu yang disimpan.timA.union(timB): menggabungkan kedua tim tanpa duplikat. Elemen yang muncul di kedua set hanya disimpan sekali.timA.intersect(timB): hanya elemen yang ada di kedua set —"Dewi"dan"Andi"— yang masuk ke hasil.timA.filter { it !in timB } + ...: membentuk symmetric difference (elemen yang hanya ada di salah satu set) secara manual. Kotlin tidak menyediakan fungsi bawaan untuk operasi ini.timA.containsAll(kecil): memeriksa apakahtimAadalah superset darikecil. Mengembalikantruekarena kedua nama dikeciljuga ada ditimA.
Referensi Lanjutan #
- Set
— panduan resmi
Set<T>read-only - Set API reference
— API reference
kotlin.collections.Set
Setelah memahami Set read-only, kita akan membahas versi mutable pada chapter berikutnya yang memungkinkan penambahan dan penghapusan elemen seiring waktu.