compareBy în Kotlin

Comparare și timp Kotlin 1.0

Creează un Comparator care compară obiectele după una sau mai multe proprietăți, în ordine; se folosește cu sortedWith.

Sintaxă
fun <T> compareBy(vararg selectors: (T) -> Comparable<*>?): Comparator<T>
inline fun <T> compareBy(crossinline selector: (T) -> Comparable<*>?): Comparator<T>

Ce face compareBy

compareBy { it.nota } creează un Comparator: o regulă de comparare după valoarea dată de bloc. Îl dai lui sortedWith, maxWith, sortWith sau unui TreeSet. Cu mai multe blocuri, compareBy({ it.oras }, { it.nume }), compară după primul criteriu, iar la egalitate după al doilea.

Comparatorul obținut se poate extinde: .thenBy { } adaugă un criteriu crescător, .thenByDescending { } unul descrescător, iar .reversed() inversează tot. Pentru un singur criteriu descrescător există compareByDescending { }. Valorile null sunt puse primele.

Parametri

Parametru Descriere
selectors: (T) -> Comparable<*>? Unul sau mai multe blocuri care dau valoarea după care se compară.

Ce returnează

Un Comparator<T>.

Exemple

Exemplul 1: Sortare după mai multe criterii

Studenții sunt ordonați după oraș; în același oraș, după nume.

data class Student(val nume: String, val oras: String, val nota: Int)

fun main() {
    val studenti = listOf(
        Student("Ion", "Iași", 8),
        Student("Ana", "Cluj", 10),
        Student("Dan", "Iași", 9),
        Student("Bia", "Cluj", 7),
    )
    studenti.sortedWith(compareBy({ it.oras }, { it.nume }))
        .forEach { println("${it.oras}: ${it.nume}") }
}

Rezultat

Cluj: Ana
Cluj: Bia
Iași: Dan
Iași: Ion

Exemplul 2: thenByDescending și maxWith

Produsele sunt ordonate după categorie, apoi de la cel mai scump la cel mai ieftin. Același fel de comparator merge și cu maxWith.

data class Produs(val nume: String, val categorie: String, val pret: Double)

fun main() {
    val produse = listOf(
        Produs("lapte", "lactate", 7.2),
        Produs("pâine", "panificație", 4.5),
        Produs("brânză", "lactate", 22.0),
        Produs("covrigi", "panificație", 3.0),
    )
    val ordine = compareBy<Produs> { it.categorie }.thenByDescending { it.pret }
    produse.sortedWith(ordine).forEach { println("${it.categorie} – ${it.nume} ${it.pret}") }
    println(produse.maxWith(compareBy { it.nume.length }))
}

Rezultat

lactate – brânză 22.0
lactate – lapte 7.2
panificație – pâine 4.5
panificație – covrigi 3.0
Produs(nume=covrigi, categorie=panificație, pret=3.0)

Greșeli frecvente

  • Scrii compareBy { it.nota }.thenBy { it.nume } fără tip și compilatorul nu poate deduce tipul. Scrie tipul explicit: compareBy<Student> { it.nota }.
  • Folosești sortedBy de două ori la rând, crezând că sortezi după două criterii. A doua sortare o înlocuiește pe prima; folosește un singur compareBy cu mai multe criterii.

Comenzi înrudite

  • Comparable.compareTo: compareTo compară două obiecte și dă un număr negativ, 0 sau pozitiv; compareValues face la fel și acceptă null.
  • maxOf: Returnează cea mai mare (maxOf) sau cea mai mică (minOf) dintre două sau mai multe valori comparabile.