comparable kotlin

comparable - ¿Cómo ordenar en base/comparar múltiples valores en Kotlin?



(1)

Digamos que tengo una class Foo(val a: String, val b: Int, val c: Date) y quiero ordenar una lista de Foo s basada en las tres propiedades. ¿Cómo voy a hacer esto?


Stdlib de Kotlin ofrece varios métodos útiles para esto.

Primero, puede definir un comparador utilizando el método compareBy() y pasarlo al método de extensión sortedWith() para recibir una copia ordenada de la lista:

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

En segundo lugar, puede dejar que Foo implemente Comparable<Foo> usando el método auxiliar compareValuesBy() :

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 }) }

Luego puede llamar al método de extensión sorted() sin parámetros para recibir una copia ordenada de la lista:

val sortedList = list.sorted()

Dirección de clasificación

Si necesita ordenar ascendente en algunos valores y descendente en otros valores, stdlib también ofrece funciones para eso:

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

Consideraciones de rendimiento

La versión vararg de compareValuesBy no está compareValuesBy en el compareValuesBy de compareValuesBy lo que significa que se generarán clases anónimas para las lambdas. Sin embargo, si las lambdas mismas no capturan el estado, se utilizarán instancias singleton en lugar de crear instancias de las lambdas cada vez.

Como señaló Paul Woitaschek en los comentarios, la comparación con múltiples selectores creará una instancia de la llamada vararg cada vez. No puede optimizar esto extrayendo la matriz, ya que se copiará en cada llamada. Lo que puede hacer, por otro lado, es extraer la lógica en una instancia de comparación estática y reutilizarla:

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) } }