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:

FungsiMengembalikanKriteria
sorted()List terurutUrutan natural
sortedDescending()List terurut menurunUrutan natural terbalik
sortedBy { key }List terurutBerdasarkan key selector
sortedByDescending { key }List terurut menurunBerdasarkan key selector terbalik
sortedWith(comparator)List terurutComparator 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:

kotlin Contoh: comparator majemuk
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 #

kotlin
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:

text
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:

  1. angka.sorted(): mengembalikan list baru [1, 2, 3, 5, 7, 8, 9] — urutan natural Int. List asli angka tidak berubah.
  2. angka.reversed(): membalik urutan elemen, bukan mengurutkan. Hasilnya [7, 3, 9, 1, 8, 2, 5] — kebalikan urutan asli.
  3. angka.shuffled(Random(42)): mengacak urutan dengan generator ber-seed. Seed 42 menjamin output yang sama lintas eksekusi — penting untuk pengujian deterministik.
  4. pegawai.sortedBy { it.gaji }: urut berdasarkan gaji ascending. Budi dan Andi (gaji 5.000.000) berada di depan karena gaji paling kecil; urutan di antara mereka tergantung stabilitas sort (Kotlin menggunakan TimSort yang stabil).
  5. compareBy<Pegawai> { it.gaji }.thenBy { it.umur }: comparator majemuk. Pertama urut berdasarkan gaji; bila sama, urut berdasarkan umur. Budi (umur 30) mendahului Andi (umur 35) karena keduanya berbagi gaji yang sama.
  6. compareBy({ it.umur }, { it.nama }): bentuk vararg comparator. Setiap lambda adalah selector untuk satu kriteria urut.
  7. compareByDescending<Pegawai> { it.gaji }.thenBy { it.umur }: gaji descending (terbesar dulu), lalu umur ascending (termuda dulu) sebagai pemecah seri.
  8. denganDuplikat.toSortedSet(): toSortedSet() menghasilkan SortedSet<T> yang otomatis mengurutkan dan membuang duplikat. Hasilnya [1, 2, 3, 4] — elemen unik terurut.
  9. m.sort(): padanan in-place untuk MutableList. Mengubah isi m secara langsung tanpa membuat list baru.

Referensi Lanjutan #

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.