Mengurutkan elemen collection adalah operasi yang sering kita temui: dari menampilkan daftar pegawai berdasarkan gaji hingga memproses antrian berdasarkan prioritas. Kotlin memisahkan operasi sorting menjadi dua keluarga: yang mengembalikan collection baru (immutable) dan yang mengurutkan in-place (mutable). Pada chapter ini kita akan mempraktikkan sorted, sortedBy, sortedWith, shuffled, reversed, dan padanan in-place mereka.
Keluarga sorted (Immutable) #
Operasi berikut mengembalikan collection baru tanpa mengubah collection asli:
| Fungsi | Mengembalikan | Kriteria |
|---|---|---|
sorted() | List terurut | Urutan natural |
sortedDescending() | List terurut menurun | Urutan natural terbalik |
sortedBy { key } | List terurut | Berdasarkan key selector |
sortedByDescending { key } | List terurut menurun | Berdasarkan key selector terbalik |
sortedWith(comparator) | List terurut | Comparator custom |
sortedBy { it.nama } adalah shortcut untuk sortedWith(compareBy { it.nama }). Untuk pengurutan majemuk (primary key lalu secondary key), gunakan compareBy { ... }.thenBy { ... }.
Comparator Majemuk #
Untuk urutan multi-kriteria, kita merangkai compareBy, thenBy, thenByDescending:
val urutMajemuk = pegawai.sortedWith(
compareBy<Pegawai> { it.gaji } // primary: gaji ascending
.thenBy { it.umur } // secondary: umur ascending
)Versi vararg compareBy({ k1 }, { k2 }, { k3 }) juga tersedia untuk comparator berurutan.
shuffled dan reversed #
shuffled() mengembalikan list baru dengan urutan acak. Tanpa argumen, ia menggunakan Random default yang tidak deterministik. Untuk pengujian, gunakan Random(42) (dengan seed) agar output konsisten.
reversed() membalik urutan elemen — bukan mengurutkan. [5, 2, 8] menjadi [8, 2, 5].
Sort In-Place (Mutable) #
Untuk MutableList, tersedia padanan yang memodifikasi list secara langsung:
| Fungsi (mutable) | Padanan immutable |
|---|---|
sort() | sorted() |
sortDescending() | sortedDescending() |
sortBy { ... } | sortedBy { ... } |
sortByDescending { ... } | sortedByDescending { ... } |
sortWith(comparator) | sortedWith(comparator) |
shuffle() | shuffled() |
reverse() | reversed() |
Contoh Lengkap #
data class Pegawai(val nama: String, val gaji: Int, val umur: Int)
fun main() {
val angka = listOf(5, 2, 8, 1, 9, 3, 7)
println("Awal: $angka")
// sorted: urut natural menaik
println("sorted: ${angka.sorted()}")
// sortedDescending: urut natural menurun
println("sortedDescending: ${angka.sortedDescending()}")
// reversed: balik urutan (bukan urut)
println("reversed: ${angka.reversed()}")
// shuffled: acak (gunakan Random ber-seed untuk deterministik)
val acak = angka.shuffled(kotlin.random.Random(42))
println("shuffled(seed=42): $acak")
// sortBy: urut berdasarkan key selector
val pegawai = listOf(
Pegawai("Budi", 5000000, 30),
Pegawai("Siti", 7000000, 25),
Pegawai("Dewi", 6000000, 28),
Pegawai("Andi", 5000000, 35)
)
val urutGaji = pegawai.sortedBy { it.gaji }
println("Sort by gaji:")
urutGaji.forEach { println(" $it") }
val urutNama = pegawai.sortedBy { it.nama }
println("Sort by nama:")
urutNama.forEach { println(" $it") }
// sortedByDescending
val urutGajiDesc = pegawai.sortedByDescending { it.gaji }
println("Sort gaji descending:")
urutGajiDesc.forEach { println(" $it") }
// sortedWith + comparator: urut majemuk (gaji lalu umur)
val urutMajemuk = pegawai.sortedWith(
compareBy<Pegawai> { it.gaji }.thenBy { it.umur }
)
println("Sort gaji lalu umur:")
urutMajemuk.forEach { println(" $it") }
// Comparator custom
val urutCustom = pegawai.sortedWith(compareBy({ it.umur }, { it.nama }))
println("Sort umur lalu nama (vararg):")
urutCustom.forEach { println(" $it") }
// thenByDescending dan thenComparator
val urutGajiDescUmurAsc = pegawai.sortedWith(
compareByDescending<Pegawai> { it.gaji }.thenBy { it.umur }
)
println("Sort gaji desc lalu umur asc:")
urutGajiDescUmurAsc.forEach { println(" $it") }
// sorted distinct: urut + buang duplikat
val denganDuplikat = listOf(3, 1, 2, 3, 2, 1, 4)
println("Distinct sorted: ${denganDuplikat.toSortedSet()}")
// Mutable: sort in-place
val m = mutableListOf(5, 2, 8, 1)
m.sort()
println("Mutable setelah sort(): $m")
m.sortDescending()
println("Mutable setelah sortDescending(): $m")
m.shuffle(kotlin.random.Random(42))
println("Mutable setelah shuffle(seed=42): $m")
}Output yang Dihasilkan:
Awal: [5, 2, 8, 1, 9, 3, 7]
sorted: [1, 2, 3, 5, 7, 8, 9]
sortedDescending: [9, 8, 7, 5, 3, 2, 1]
reversed: [7, 3, 9, 1, 8, 2, 5]
shuffled(seed=42): [8, 3, 9, 1, 2, 5, 7]
Sort by gaji:
Pegawai(nama=Budi, gaji=5000000, umur=30)
Pegawai(nama=Andi, gaji=5000000, umur=35)
Pegawai(nama=Dewi, gaji=6000000, umur=28)
Pegawai(nama=Siti, gaji=7000000, umur=25)
Sort by nama:
Pegawai(nama=Andi, gaji=5000000, umur=35)
Pegawai(nama=Budi, gaji=5000000, umur=30)
Pegawai(nama=Dewi, gaji=6000000, umur=28)
Pegawai(nama=Siti, gaji=7000000, umur=25)
Sort gaji descending:
Pegawai(nama=Siti, gaji=7000000, umur=25)
Pegawai(nama=Dewi, gaji=6000000, umur=28)
Pegawai(nama=Budi, gaji=5000000, umur=30)
Pegawai(nama=Andi, gaji=5000000, umur=35)
Sort gaji lalu umur:
Pegawai(nama=Budi, gaji=5000000, umur=30)
Pegawai(nama=Andi, gaji=5000000, umur=35)
Pegawai(nama=Dewi, gaji=6000000, umur=28)
Pegawai(nama=Siti, gaji=7000000, umur=25)
Sort umur lalu nama (vararg):
Pegawai(nama=Siti, gaji=7000000, umur=25)
Pegawai(nama=Dewi, gaji=6000000, umur=28)
Pegawai(nama=Budi, gaji=5000000, umur=30)
Pegawai(nama=Andi, gaji=5000000, umur=35)
Sort gaji desc lalu umur asc:
Pegawai(nama=Siti, gaji=7000000, umur=25)
Pegawai(nama=Dewi, gaji=6000000, umur=28)
Pegawai(nama=Budi, gaji=5000000, umur=30)
Pegawai(nama=Andi, gaji=5000000, umur=35)
Distinct sorted: [1, 2, 3, 4]
Mutable setelah sort(): [1, 2, 5, 8]
Mutable setelah sortDescending(): [8, 5, 2, 1]
Mutable setelah shuffle(seed=42): [2, 5, 1, 8]Mari kita bedah baris-baris penting di atas:
angka.sorted(): mengembalikan list baru[1, 2, 3, 5, 7, 8, 9]— urutan naturalInt. List asliangkatidak berubah.angka.reversed(): membalik urutan elemen, bukan mengurutkan. Hasilnya[7, 3, 9, 1, 8, 2, 5]— kebalikan urutan asli.angka.shuffled(Random(42)): mengacak urutan dengan generator ber-seed. Seed42menjamin output yang sama lintas eksekusi — penting untuk pengujian deterministik.pegawai.sortedBy { it.gaji }: urut berdasarkan gaji ascending.BudidanAndi(gaji5.000.000) berada di depan karena gaji paling kecil; urutan di antara mereka tergantung stabilitas sort (Kotlin menggunakan TimSort yang stabil).compareBy<Pegawai> { it.gaji }.thenBy { it.umur }: comparator majemuk. Pertama urut berdasarkan gaji; bila sama, urut berdasarkan umur.Budi(umur 30) mendahuluiAndi(umur 35) karena keduanya berbagi gaji yang sama.compareBy({ it.umur }, { it.nama }): bentuk vararg comparator. Setiap lambda adalah selector untuk satu kriteria urut.compareByDescending<Pegawai> { it.gaji }.thenBy { it.umur }: gaji descending (terbesar dulu), lalu umur ascending (termuda dulu) sebagai pemecah seri.denganDuplikat.toSortedSet():toSortedSet()menghasilkanSortedSet<T>yang otomatis mengurutkan dan membuang duplikat. Hasilnya[1, 2, 3, 4]— elemen unik terurut.m.sort(): padanan in-place untukMutableList. Mengubah isimsecara langsung tanpa membuat list baru.
Referensi Lanjutan #
- Collection ordering
— panduan resmi
sorted,sortedBy,sortedDescending,reversed - Collection operations — tinjauan umum operasi pengurutan
Setelah menguasai pengurutan, kita akan melihat operasi yang meringkas seluruh collection menjadi satu nilai: sum, average, max, min, reduce, fold akan dibahas pada chapter aggregating.