Distinguish reversed(), asReversed(), and sortedDescending(). What does reversing a comparator with reversed() do, and how does stability interact with these?
answer
- reversed() flips order, does NOT sort
- asReversed() = live view, no copy
- sortedDescending() truly sorts high→low
- sorted().reversed() breaks tie stability; sortedDescending preserves it
- comparator.reversed() inverts ALL levels
basics
~20 sreversed() flips the current order into a new list. asReversed() gives a live reversed view without copying. sortedDescending() actually sorts from high to low. Reversing a list is not the same as sorting it descending.
solid answer
~40 sreversed() returns a new List with elements in the opposite of their current positional order — it does not sort, it just flips whatever order exists. asReversed() returns a lightweight reversed view backed by the original (no copy; changes to a MutableList show through, and writes via the view mutate the source). sortedDescending() genuinely sorts by natural order descending. Critically, sorted().reversed() is NOT the same as sortedDescending() when there are equal elements: descending sort is stable and keeps equal elements in original order, whereas ascending-then-reverse inverts the relative order of equal elements. On comparators, comparator.reversed() inverts the full ordering including every thenBy tie-break level — different from per-key thenByDescending. Prefer sortedDescending()/sortedByDescending for correct descending sorts.
code
kotlin · 10 linesdata class P(val k: Int, val tag: String)
val xs = listOf(P(1,"a"), P(1,"b"), P(2,"c"))
println(xs.sortedByDescending { it.k }) // [P(2,c), P(1,a), P(1,b)]
println(xs.sortedBy { it.k }.reversed()) // [P(2,c), P(1,b), P(1,a)] ties flipped!
val big = mutableListOf(1, 2, 3)
val view = big.asReversed() // [3, 2, 1] (no copy)
big.add(4)
println(view) // [4, 3, 2, 1]go deeper
Knows reversed() flips order and is not the same as sorting.
Distinguishes reversed() (copy) from sortedDescending() (sort) and knows asReversed() avoids a copy.
Explains the stability trap where sorted().reversed() flips ties vs stable sortedByDescending, and what comparator.reversed() does.
Reasons about correctness of stable ordering as a contract, picks asReversed views for memory on hot paths, and audits code for the reverse-after-sort tie bug.
## Three different operations ### reversed() `list.reversed()` returns a **new `List`** with the same elements in opposite positional order. It performs **no sorting** — `listOf(3,1,2).reversed()` is `[2,1,3]`. It simply flips index order. ### asReversed() `list.asReversed()` returns a **reversed view** without copying. For a `List` it's a read-only reversed window; for a `MutableList` the view is writable and writes propagate to the source. Iterating it is O(1) to create and O(n) to traverse, but no new backing array is allocated — useful for large lists when you only need reverse iteration. ```kotlin val m = mutableListOf(1, 2, 3) val view = m.asReversed() // [3, 2, 1] live view m.add(4) // view now reflects [4, 3, 2, 1] ``` ### sortedDescending() Actually orders by natural ordering from high to low. `listOf(3,1,2).sortedDescending()` is `[3,2,1]`. ## The stability trap: sorted().reversed() vs sortedDescending() Kotlin's sort is **stable** — equal elements keep input order. Consider sorting by a key where ties exist: ```kotlin data class P(val k: Int, val tag: String) val xs = listOf(P(1,"a"), P(1,"b"), P(2,"c")) xs.sortedByDescending { it.k } // [P(2,c), P(1,a), P(1,b)] -- ties keep a,b order xs.sortedBy { it.k }.reversed() // [P(2,c), P(1,b), P(1,a)] -- ties FLIPPED to b,a ``` Because `reversed()` flips everything (including equal-key elements), it breaks stability for ties. `sortedByDescending` preserves it. This is a classic subtle bug. ## Reversing a comparator `comparator.reversed()` inverts the **entire** ordering, every tie-break level included: ```kotlin val cmp = compareBy<P>({ it.k }, { it.tag }) xs.sortedWith(cmp.reversed()) // fully inverted on both keys ``` This differs from `thenByDescending`, which flips only one level. Choose deliberately. ## Summary guidance - Need reverse **iteration order** of existing order, no copy → `asReversed()`. - Need a reversed **copy** → `reversed()`. - Need a true descending **sort** → `sortedDescending()` / `sortedByDescending` (stable).
- Why can sorted().reversed() give a different result than sortedDescending()?Sort is stable, so descending sort keeps equal elements in input order; reversing an ascending sort also flips the relative order of equal elements, breaking that stability.
- When is asReversed() preferable to reversed()?When you only need reverse iteration over a large list and want to avoid allocating a copy — asReversed() returns a live, backing view.
- What does comparator.reversed() do to tie-break levels?It inverts the whole ordering, every thenBy level included — unlike thenByDescending which flips just one level.
saying these in an interview costs you the question
- Saying reversed() sorts the list
- Claiming sorted().reversed() always equals sortedDescending()
- Not knowing asReversed() is a non-copying live view
- Thinking comparator.reversed() only flips the primary key