Ordenar una lista en Kotlin es una línea, pero hay decisiones que cambian el resultado: si ordenas la lista o creas otra, en qué idioma comparas el texto y qué pasa cuando buscas algo que no está. Esta página las repasa con ejemplos que puedes copiar.
También te puede interesar
Ordenar números
fun main() {
val notas = listOf(7, 3, 9, 3, 10, 5)
println(notas.sorted())
println(notas.sortedDescending())
println(notas)
val mutable = mutableListOf(7, 3, 9, 3, 10, 5)
mutable.sort()
println(mutable)
mutable.sortDescending()
println(mutable)
}salida[3, 3, 5, 7, 9, 10] [10, 9, 7, 5, 3, 3] [7, 3, 9, 3, 10, 5] [3, 3, 5, 7, 9, 10] [10, 9, 7, 5, 3, 3]
Kotlin distingue entre dos familias de funciones. sorted() y sortedDescending() devuelven una lista nueva y dejan la original como estaba: por eso el tercer println sigue mostrando el orden de partida. sort() y sortDescending() ordenan la propia lista, y solo existen para listas mutables.
Si intentas ordenar en su sitio una lista de solo lectura, el compilador te detiene:
fun main() {
val notas = listOf(7, 3, 9)
notas.sort()
println(notas)
}kotlincsort_lectura.kt:3:11: error: unresolved reference 'sort' on receiver of type 'List<Int>'.
notas.sort()
^^^^El mensaje parece raro («no encuentro sort»), pero tiene sentido: sort es una función de MutableList, y listOf devuelve un List, que no la tiene. O usas sorted() y guardas el resultado, o creas la lista con mutableListOf.
Ordenar texto: depende del idioma
import java.text.Collator
import java.util.Locale
fun main() {
val palabras = listOf("ñu", "nube", "Zorro", "árbol", "abeja", "oso")
println("sorted(): " + palabras.sorted())
println("ignoreCase: " + palabras.sortedWith(String.CASE_INSENSITIVE_ORDER))
val espanol = Collator.getInstance(Locale.forLanguageTag("es-MX"))
println("es-MX: " + palabras.sortedWith(espanol))
}salidasorted(): [Zorro, abeja, nube, oso, árbol, ñu] ignoreCase: [abeja, nube, oso, Zorro, árbol, ñu] es-MX: [abeja, árbol, nube, ñu, oso, Zorro]
sorted() compara los códigos de los caracteres: todas las mayúsculas van antes que las minúsculas, y las letras con acento y la ñ, al final. CASE_INSENSITIVE_ORDER arregla las mayúsculas, pero «árbol» y «ñu» siguen fuera de lugar. Para un orden que entienda una persona hay que usar un Collator del idioma: con es-MX, «árbol» va con la a y la ñ va después de la n.
Ordenar objetos por varios campos
data class Producto(val nombre: String, val categoria: String, val precio: Double)
fun main() {
val productos = listOf(
Producto("Café molido", "bebidas", 89.50),
Producto("Galletas", "dulces", 32.00),
Producto("Té verde", "bebidas", 54.90),
Producto("Chocolate", "dulces", 32.00),
Producto("Cacao puro", "bebidas", 120.00),
)
val ordenados = productos.sortedWith(
compareBy<Producto> { it.categoria }
.thenByDescending { it.precio }
.thenBy { it.nombre }
)
for (p in ordenados) {
println("${p.categoria.padEnd(8)} ${"%7.2f".format(p.precio)} ${p.nombre}")
}
println(productos.sortedBy { it.precio }.map { it.nombre })
println(productos.maxBy { it.precio }.nombre)
}salidabebidas 120.00 Cacao puro bebidas 89.50 Café molido bebidas 54.90 Té verde dulces 32.00 Chocolate dulces 32.00 Galletas [Galletas, Chocolate, Té verde, Café molido, Cacao puro] Cacao puro
sortedBy ordena por un solo campo. Para varios, compareBy crea un comparador y thenBy / thenByDescending añaden criterios de desempate: aquí, primero la categoría, luego el precio de mayor a menor y, a igual precio, el nombre. El orden es estable: lo que empata en todo conserva el orden en que estaba. Para quedarte solo con el mayor o el menor no hace falta ordenar: maxBy y minBy recorren la lista una vez.
Buscar
data class Producto(val nombre: String, val precio: Double)
fun main() {
val productos = listOf(
Producto("Café molido", 89.50), Producto("Té verde", 54.90), Producto("Cacao puro", 120.00),
)
println(productos.find { it.precio < 60 }?.nombre)
println(productos.indexOfFirst { it.nombre.startsWith("Cacao") })
println(productos.indexOfFirst { it.nombre.startsWith("Miel") })
println(productos.any { it.precio > 200 })
println(productos.firstOrNull { it.precio > 200 }?.nombre ?: "(ninguno)")
println(productos.count { it.precio > 60 })
println(productos.filter { it.precio > 60 }.map { it.nombre })
val caro = productos.first { it.precio > 200 }
println(caro)
}salida con errorTé verde 2 -1 false (ninguno) 2 [Café molido, Cacao puro] Exception in thread "main" java.util.NoSuchElementException: Collection contains no element matching the predicate.
find (que es lo mismo que firstOrNull) devuelve null si nada cumple la condición, e indexOfFirst devuelve -1. Con el operador ?: das un valor por omisión en la misma línea. Pero first lanza una excepción si no encuentra nada, que es lo que pasa al final. Usa first solo cuando que no exista sea un error de verdad, y firstOrNull cuando sea una posibilidad normal: el tipo Producto? te obliga a decidir qué hacer en ese caso.
Búsqueda binaria
Buscar recorriendo la lista es lento si la lista es enorme. Si está ordenada, la búsqueda binaria mira el elemento del centro y descarta la mitad en la que no puede estar, una y otra vez:
fun main() {
val ordenados = listOf(3, 8, 12, 19, 23, 31, 40, 52)
println(ordenados.binarySearch(31))
val i = ordenados.binarySearch(20)
println("$i -> iría en la posición ${-(i + 1)}")
val desordenados = listOf(40, 31, 3, 8, 52, 19)
println(desordenados.binarySearch(31))
val nombres = listOf("Ana", "Beto", "Carla", "Diego")
println(nombres.binarySearch { it.compareTo("Carla") })
}salida5 -5 -> iría en la posición 4 -5 2
Si lo encuentra, binarySearch devuelve el índice. Si no, un número negativo que codifica dónde habría que insertarlo para mantener el orden: -(i + 1). La tercera línea es la trampa: con una lista desordenada no da error, da una respuesta equivocada (un negativo, «no está», aunque el 31 está en la posición 1). Ordena antes, o usa un Set si solo necesitas saber si algo está. La última forma recibe una función de comparación, útil para buscar por un campo en una lista de objetos ordenada por ese campo.
- QuieresLista nuevaEn su sitio (MutableList)
- Orden natural
sorted()sort() - Al revés
sortedDescending()sortDescending() - Por un campo
sortedBy { it.precio }sortBy { it.precio } - Varios criterios
sortedWith(compareBy(...).thenBy(...))sortWith(...)
Si vienes de Java: Collections.sort y Comparator
En Java, Collections.sort(lista) ordena en su sitio y lista.stream().sorted() crea otra. Kotlin hace la diferencia visible en el nombre (sort frente a sorted) y en el tipo (List frente a MutableList). compareBy y thenBy equivalen a Comparator.comparing y thenComparing. Compara con ordenar y buscar en Java.
Todo el código de esta página se compiló con Kotlin 2.4.21 y se ejecutó en la JVM de Temurin 25.0.5 en un contenedor limpio y sin red antes de publicarla; las salidas y los mensajes del compilador están copiados de esa ejecución.