Kotlin: Put May as the first in the list
Video: Kotlin: Put May as the first in the list by Taught by Celeste AI - AI Coding Coach
Kotlin: Put "May" First in a List of Months
sortedWith(compareBy { ... })plus a custom comparator key. The trick: assign 0 to "May" and 1 to everything else — stable sort puts May first while preserving the rest of the order.
A small list-reordering puzzle that demos how Kotlin's compareBy plus a one-line lambda can prioritise specific elements without writing a manual loop.
The task
Given ["January", "February", ..., "July"], produce a new list where "May" is first but the rest stay in their original order.
The Copilot prompt
fun main() {
val months = listOf("January", "February", "March", "April", "May", "June", "July")
// Move "May" to the front while keeping the order of other months
The comment is the spec. Copilot reads "move May to the front" and "keeping the order" — two constraints — and produces:
val reordered = months.sortedWith(compareBy { if (it == "May") 0 else 1 })
println(reordered)
// Output: [May, January, February, March, April, June, July]
Walkthrough
sortedWith(comparator) produces a new sorted list (the original is untouched). The comparator decides ordering.
compareBy { selector } is a Kotlin stdlib helper that builds a comparator from a "key" function. Each element is mapped to a key; the comparator sorts by those keys ascending.
The key here is if (it == "May") 0 else 1. So:
"May"maps to0.- Every other month maps to
1.
When sorted ascending, 0 comes before 1 — May lands at the front. Among the 1-keyed elements, Kotlin's sort is stable: equal-keyed elements keep their original order. That's why "January, February, March, April, June, July" preserves their input order.
Without compareBy
The same logic spelled out:
val reordered = months.sortedWith(Comparator { a, b ->
val keyA = if (a == "May") 0 else 1
val keyB = if (b == "May") 0 else 1
keyA.compareTo(keyB)
})
compareBy is sugar for "build this comparator from a key function." Always shorter.
A simpler approach
If you don't need the elegance of a comparator, a partition is more direct:
val (may, others) = months.partition { it == "May" }
val reordered = may + others
partition splits the list in two by a predicate — first part matches, second doesn't. + joins them. Same result.
For a single sentinel, partition + concat is arguably clearer than sortedWith. For prioritising multiple values (May first, June second, then the rest), compareBy scales better:
val priority = mapOf("May" to 0, "June" to 1)
val reordered = months.sortedWith(compareBy { priority[it] ?: 2 })
Refining the Copilot comment
If you write only "// reorder list to put May first," Copilot might produce:
val reordered = months.toMutableList()
reordered.remove("May")
reordered.add(0, "May")
Functional but mutates. To steer Copilot toward the immutable, idiomatic version:
"Move 'May' to the front while keeping the order of other months. Return a new list."
Mentioning "return a new list" nudges away from in-place mutation.
Stability matters
The reason this works at all is that Kotlin's sortedWith is stable — equal keys preserve insertion order. If it weren't, the 1-keyed months might come out in any order.
Collections.sort (Java) and sortedWith (Kotlin) both use Timsort, which is stable. Don't use unstable sorts (raw quicksort, hash-based) when relative order of equal elements matters.
Extension to "any priority list"
fun <T> List<T>.prioritize(target: T): List<T> =
sortedWith(compareBy { if (it == target) 0 else 1 })
println(months.prioritize("May"))
println(months.prioritize("July"))
Generic, reusable. Add it to a Lists.kt file once, use everywhere.
Common mistakes
Forgetting that sortedWith returns a new list. months.sortedWith(...) doesn't change months. Many bugs come from "I sorted it but the list looks the same" — you have to assign the result.
Using sort (mutating) on a listOf. listOf(...) returns a List<T> (read-only). sort is on MutableList. Reach for sortedWith (immutable).
Comparator returning Boolean. compareBy { it == "May" } works in Kotlin (Boolean is Comparable, false < true), but the meaning is reversed — false (others) sorts before true (May), so May ends up last. Use the explicit 0/1 form to avoid the surprise.
Expecting alphabetical preservation. The "other months" come out in input order, not alphabetical. If you want "May first, then alphabetical," chain comparators:
months.sortedWith(
compareBy<String> { if (it == "May") 0 else 1 }
.thenBy { it }
)
thenBy { it } says "then by the element itself, alphabetically."
Common Copilot habits
When Copilot generates Kotlin list operations, it tends to reach for:
filter,map,sortedBy,groupBy— the functional staples.toMutableList()+ manualadd/removewhen the comment hints at "modify."compareBy { ... }for any sort-with-criteria task.
Steering with comments shapes which style you get. "Return a new list" → functional. "Modify the list" → mutable.
What's next
Episode 3: Convert a string to a Date in Kotlin. Old-school SimpleDateFormat versus the modern LocalDate.parse — which one does Copilot reach for, and which should you keep?
Recap
sortedWith(compareBy { selector }) for custom-key sorting. Returns a new list — Kotlin's stable sort preserves input order among equal keys. Alternatives: partition + concat for single-sentinel priority; a Map of priorities for multi-tier. Steer Copilot away from mutations with "return a new list" in the comment. Comparator returning Boolean has reversed semantics — use 0/1.
Next episode: convert a string to a date.