¿Cómo orderar basado en / comparar múltiples valores en Kotlin?

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

Kotlin's stdlib ofrece varios methods útiles de ayuda para esto.

Primero, puede definir un comparador usando el método compareBy() y pasarlo al método de extensión sortedWith() para recibir una copy orderada de la list:

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

En segundo lugar, puede permitir que Foo implemente Comparable<Foo> utilizando el método de ayuda 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 parameters para recibir una copy orderada de la list:

 val sortedList = list.sorted() 

Dirección de sorting

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

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

Consideraciones de performance

La versión vararg de compareValuesBy no está en línea en bytecode, lo que significa que se generarán classs anónimas para las lambdas. Sin embargo, si las lambdas no capturan el estado, se usarán instancias únicas en lugar de instanciar las lambdas cada vez.

Como señaló Paul Woitaschek en los comentarios, la comparación con selectores múltiples instanciará una matriz para la llamada vararg cada vez. No puede optimizar esto extrayendo la matriz, ya que se copyrá en cada llamada. Lo que puede hacer, por otro lado, es extraer la lógica en una instancia comparativa 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) } } 
  • ¿Es posible express kotlin 'con' método equivalente en Scala?
  • Kotlin: declara una class genérica con un tipo param que es genérico
  • ¿Es posible asignar una function de order superior en kotlin a una cadena?
  • ¿Los nativos de kotlin tienen destructores?
  • Kotlin y Spring Boot @ConfigurationProperties
  • ¿Por qué para el loop con comstackciones de tres puntos?
  • Android w / Kotlin pure-java-Junit NoClassDefFoundError solución no funciona
  • Mocktito ArgumentCaptor para Kotlin lambda con arguments
  • ¿Cómo llamar al método Kotlin con más de una firma similar con lambda?
  • La notificación de consulta de dominio no se activa con Kotlin
  • No se puede burlar de la class final de Kotlin usando Mockito 2