Comment trier sur / Comparer des valeurs multiples dans Kotlin?

dire que j'ai un class Foo(val a: String, val b: Int, val c: Date) et je veux trier une liste de Foo s basé sur les trois propriétés. Comment pourrais-je aller à ce sujet?

47
demandé sur Kirill Rakhman 2015-11-11 01:27:46

1 réponses

Kotlin du stdlib propose un certain nombre de méthodes d'aide pour cela.

tout D'abord, vous pouvez définir un comparateur en utilisant la compareBy() méthode et passer à la sortedWith() méthode d'extension pour recevoir une copie triée de la liste:

val list: List<Foo> = ...
val sortedList = list.sortedWith(compareBy({ it.a }, { it.b }, { it.c }))

Deuxièmement, vous pouvez laisser Foo mettre en œuvre Comparable<Foo> en utilisant la compareValuesBy() méthode d'aide:

class Foo(val a: String, val b: Int, val c: Date) : Comparable<Foo> {
    override fun compareTo(other: Foo)
            = compareValuesBy(this, other, { it.a }, { it.b }, { it.c })
}

alors vous pouvez appeler la sorted() méthode d'extension sans paramètres pour recevoir une copie triée de la liste:

val sortedList = list.sorted()

direction de tri

si vous avez besoin de trier ascendant sur certaines valeurs et descendant sur d'autres valeurs, le stdlib offre également des fonctions pour cela:

list.sortedWith(compareBy<Foo> { it.a }.thenByDescending { it.b }.thenBy { it.c })

facteurs de Performance

le La version vararg de compareValuesBy n'est pas insérée dans le bytecode, ce qui signifie que des classes anonymes seront générées pour les lambdas. Cependant, si les lambdas eux-mêmes ne capturent pas l'état, des instances uniques seront utilisées au lieu d'instancier les lambdas à chaque fois.

Comme l'a noté Paul Woitaschek dans les commentaires, la comparaison avec plusieurs sélecteurs va instancier un tableau pour le vararg appel à chaque fois. Vous ne pouvez pas optimiser ce par extraire le tableau comme il sera copié sur chaque appel. Ce que vous pouvez faire, d'un autre côté, c'est extraire la logique dans une instance de comparaison statique et la réutiliser:

class Foo(val a: String, val b: Int, val c: Date) : Comparable<Foo> {

    override fun compareTo(other: Foo) = comparator.compare(this, other)

    companion object {
        // using the method reference syntax as an alternative to lambdas
        val comparator = compareBy(Foo::a, Foo::b, Foo::c)
    }
}
84
répondu Kirill Rakhman 2017-06-07 13:45:45