skip to content

How do you sort a List in Kotlin, and what is the difference between sorted(), sortedBy { }, and sortedDescending()?

level: juniorimportance: must knowfreq 80%

answer

  1. sorted* returns a new List, never mutates
  2. sorted() needs Comparable (natural order)
  3. sortedBy { } sorts by an extracted key
  4. Descending: sortedDescending / sortedByDescending
  5. sort() (no 'ed') mutates a MutableList in place

basics

~20 s

Use sorted() to order items from low to high. Use sortedBy { } to sort by a chosen property. Use sortedDescending() for high to low. All three return a new list and leave the original unchanged.

solid answer

~40 s

On a read-only List, sorted() returns a new List ordered by the elements' natural ordering (they must be Comparable, like Int or String). sortedBy { selector } returns a new List ordered by a key you extract per element, e.g. people.sortedBy { it.age }; the selector's result must be Comparable. sortedDescending() reverses natural order, and sortedByDescending { } reverses by a selector. None of these mutate the receiver — they always allocate and return a fresh List. This contrasts with sort()/sortBy() on a MutableList, which reorder in place and return Unit. For custom multi-key logic use sortedWith(comparator). Sorting is stable: equal elements keep their original relative order.

code

kotlin · 7 lines
kotlin
val nums = listOf(3, 1, 2)
println(nums.sorted())            // [1, 2, 3], nums unchanged
println(nums.sortedDescending())  // [3, 2, 1]

val words = listOf("banana", "fig", "apple")
println(words.sortedBy { it.length })           // [fig, apple, banana]
println(words.sortedByDescending { it.length }) // [banana, apple, fig]

go deeper

for a junior

Knows sorted/sortedBy/sortedDescending exist and return a new list ordered as named.

for a middle

Explains the Comparable requirement, stability, and that sortedBy builds a comparator from a selector.

for a senior

Contrasts sorted* (copy) with sort* (in-place), discusses stability guarantees and when to reach for sortedWith.

for a principal

Reasons about allocation cost of copying vs in-place, stability as an API contract callers depend on, and library-API ergonomics of selector-based vs comparator-based overloads.

## Natural ordering and Comparable Kotlin's `sorted()` orders elements by their **natural ordering**, defined by the `Comparable<T>` interface and its `compareTo` method. Types like `Int`, `Long`, `String`, and `Char` implement `Comparable`, so `listOf(3,1,2).sorted()` gives `[1,2,3]`. Calling `sorted()` on a list whose elements are not `Comparable` is a compile error. ## The non-mutating sorted* family These extension functions on `Iterable`/`Array` all **return a new `List`** and never change the receiver: - `sorted()` — ascending natural order. - `sortedDescending()` — descending natural order. - `sortedBy { selector }` — ascending by a key extracted from each element; the key must be `Comparable`. - `sortedByDescending { selector }` — descending by that key. - `sortedWith(comparator)` — order by an explicit `Comparator`. ```kotlin data class Person(val name: String, val age: Int) val people = listOf(Person("Ann", 30), Person("Bo", 22)) val byAge = people.sortedBy { it.age } // [Bo, Ann] val byAgeDesc = people.sortedByDescending { it.age } // [Ann, Bo] val names = listOf("c","a","b").sorted() // [a, b, c] // 'people' is unchanged after all of the above ``` ## sortedBy vs sortedWith `sortedBy { it.age }` is shorthand; under the hood it builds a `Comparator` via `compareBy`. Use `sortedWith` when you need multiple keys or custom comparison (`sortedWith(compareBy({ it.lastName }, { it.firstName }))`). ## Stability Kotlin's sort is **stable**: elements that compare equal keep their original relative order. This matters when sorting by a single key — ties stay in input order. ## Don't confuse with in-place sort `sort()`, `sortBy { }`, `sortDescending()` exist only on `MutableList` (and arrays), reorder elements **in place**, and return `Unit`. Use the `sorted*` family for read-only lists or when you must preserve the original.

  • What happens if you call sorted() on a List<SomeType> where SomeType isn't Comparable?
    It won't compile — sorted() is only available when the element type implements Comparable. You must use sortedBy/sortedWith with a comparator instead.
  • Does sortedBy mutate the original list?
    No. The entire sorted* family returns a new List and leaves the receiver untouched; only sort*/sortBy on MutableList mutate.

sorted() is like photocopying your contacts and alphabetizing the copy; sort() is rewriting the original list in place.

saying these in an interview costs you the question

  • Claiming sorted() sorts the list in place
  • Thinking sortedBy mutates the original collection
  • Believing sorted() works on any type without Comparable
  • Confusing sorted() (returns List) with sort() (returns Unit)

context