Skip to main content

Kotlin Collection Ordering

When working with collections in Kotlin, you often need to arrange elements in a specific order. Kotlin provides a rich set of functions to sort and order collections in various ways. This guide will walk you through the different methods to order collections in Kotlin, from basic sorting to advanced custom comparisons.

Introduction to Collection Ordering

Ordering (or sorting) is the process of arranging elements in a collection according to a specific sequence. Kotlin collections can be ordered in:

  • Natural order (alphabetical for strings, numerical for numbers)
  • Custom order defined by comparator functions
  • Reversed order
  • Random order

Understanding these ordering operations is essential for efficiently working with collections in your applications.

Natural Ordering

The simplest way to order a collection is using its natural ordering.

sorted() and sortedDescending()

The sorted() function returns a new list with elements sorted according to their natural order:

kotlin
fun main() {
val numbers = listOf(5, 2, 10, 4, 3, 8, 1)
val sortedNumbers = numbers.sorted()

println("Original: $numbers")
println("Sorted: $sortedNumbers")

val words = listOf("apple", "zebra", "banana", "orange")
val sortedWords = words.sorted()

println("\nOriginal words: $words")
println("Sorted words: $sortedWords")

// For descending order
val descendingNumbers = numbers.sortedDescending()
println("\nDescending numbers: $descendingNumbers")
}

Output:

Original: [5, 2, 10, 4, 3, 8, 1]
Sorted: [1, 2, 3, 4, 5, 8, 10]

Original words: [apple, zebra, banana, orange]
Sorted words: [apple, banana, orange, zebra]

Descending numbers: [10, 8, 5, 4, 3, 2, 1]

Sorting Mutable Collections

If you're working with mutable lists, you can sort them in place:

kotlin
fun main() {
val mutableNumbers = mutableListOf(5, 2, 10, 4, 3, 8, 1)

println("Before sorting: $mutableNumbers")
mutableNumbers.sort() // Sorts in place
println("After sorting: $mutableNumbers")

mutableNumbers.sortDescending() // Sorts in place in descending order
println("After sorting in descending order: $mutableNumbers")
}

Output:

Before sorting: [5, 2, 10, 4, 3, 8, 1]
After sorting: [1, 2, 3, 4, 5, 8, 10]
After sorting in descending order: [10, 8, 5, 4, 3, 2, 1]

Custom Ordering

Often you'll need to sort collections based on specific properties or custom logic.

sortedBy() and sortedByDescending()

These functions allow sorting based on a specific property:

kotlin
fun main() {
data class Person(val name: String, val age: Int)

val people = listOf(
Person("Alice", 29),
Person("Bob", 31),
Person("Charlie", 24),
Person("Diana", 35)
)

// Sort by age
val sortedByAge = people.sortedBy { it.age }
println("Sorted by age:")
sortedByAge.forEach { println("${it.name}: ${it.age}") }

// Sort by name
val sortedByName = people.sortedBy { it.name }
println("\nSorted by name:")
sortedByName.forEach { println("${it.name}: ${it.age}") }

// Sort by age descending
val sortedByAgeDescending = people.sortedByDescending { it.age }
println("\nSorted by age descending:")
sortedByAgeDescending.forEach { println("${it.name}: ${it.age}") }
}

Output:

Sorted by age:
Charlie: 24
Alice: 29
Bob: 31
Diana: 35

Sorted by name:
Alice: 29
Bob: 31
Charlie: 24
Diana: 35

Sorted by age descending:
Diana: 35
Bob: 31
Alice: 29
Charlie: 24

Using sortedWith() and compareBy()

For more complex sorting logic or multiple criteria, you can use sortedWith() and compareBy():

kotlin
fun main() {
data class Student(val name: String, val grade: String, val score: Int)

val students = listOf(
Student("Alice", "A", 92),
Student("Bob", "B", 85),
Student("Charlie", "A", 95),
Student("Diana", "B", 88),
Student("Eve", "A", 92)
)

// Sort by grade, then by score (descending)
val sortedStudents = students.sortedWith(
compareBy<Student> { it.grade }
.thenByDescending { it.score }
)

println("Students sorted by grade, then by score (descending):")
sortedStudents.forEach {
println("${it.name}: Grade ${it.grade}, Score ${it.score}")
}
}

Output:

Students sorted by grade, then by score (descending):
Charlie: Grade A, Score 95
Alice: Grade A, Score 92
Eve: Grade A, Score 92
Diana: Grade B, Score 88
Bob: Grade B, Score 85

Reversing Collections

Sometimes you just need to reverse the order of elements.

reversed() and asReversed()

kotlin
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

// Creates a new list with elements in reversed order
val reversedNumbers = numbers.reversed()
println("Original: $numbers")
println("Reversed: $reversedNumbers")

// For mutable lists, asReversed() creates a view
val mutableNumbers = mutableListOf(1, 2, 3, 4, 5)
val reversedView = mutableNumbers.asReversed()

println("\nMutable list: $mutableNumbers")
println("Reversed view: $reversedView")

// Changes to original list reflect in the reversed view
mutableNumbers.add(6)
println("\nAfter adding 6 to original list:")
println("Original: $mutableNumbers")
println("Reversed view: $reversedView")
}

Output:

Original: [1, 2, 3, 4, 5]
Reversed: [5, 4, 3, 2, 1]

Mutable list: [1, 2, 3, 4, 5]
Reversed view: [5, 4, 3, 2, 1]

After adding 6 to original list:
Original: [1, 2, 3, 4, 5, 6]
Reversed view: [6, 5, 4, 3, 2, 1]

Random Ordering

Kotlin also provides a way to shuffle elements:

kotlin
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

// Creates a new list with randomly ordered elements
val shuffled = numbers.shuffled()

println("Original: $numbers")
println("Shuffled: $shuffled")

// For mutable lists, shuffle in place
val mutableNumbers = numbers.toMutableList()
mutableNumbers.shuffle()
println("Shuffled in place: $mutableNumbers")

// You can also provide a Random instance for deterministic shuffling
val seedRandom = java.util.Random(42) // Same seed will produce same shuffle
println("Deterministic shuffle: ${numbers.shuffled(seedRandom)}")
}

Output (your results will vary for the random shuffles):

Original: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Shuffled: [5, 3, 8, 1, 9, 7, 10, 2, 6, 4]
Shuffled in place: [7, 9, 6, 3, 10, 1, 2, 5, 4, 8]
Deterministic shuffle: [1, 10, 7, 6, 9, 8, 5, 2, 3, 4]

Practical Example: Creating a Custom Sort for a Task List

Let's see how we might use these concepts to create a task list application:

kotlin
fun main() {
data class Task(
val title: String,
val priority: Int, // 1 = high, 2 = medium, 3 = low
val dueDate: String,
val isCompleted: Boolean
)

val tasks = listOf(
Task("Complete project", 1, "2023-10-15", false),
Task("Review code", 2, "2023-10-12", false),
Task("Update documentation", 3, "2023-10-20", false),
Task("Fix bug #42", 1, "2023-10-10", false),
Task("Weekly report", 2, "2023-10-08", true),
Task("Team meeting", 2, "2023-10-09", false)
)

// Sort tasks: incomplete first, then by priority, then by due date
val sortedTasks = tasks.sortedWith(
compareBy<Task> { it.isCompleted } // false comes before true
.thenBy { it.priority } // lower priority number (higher importance) first
.thenBy { it.dueDate } // earlier dates first
)

println("Task List (sorted by completion status, priority, and due date):")
println("-----------------------------------------------------------------")
sortedTasks.forEach { task ->
val status = if (task.isCompleted) "[DONE]" else "[TODO]"
val priorityText = when(task.priority) {
1 -> "High"
2 -> "Medium"
else -> "Low"
}
println("$status ${task.title} (Priority: $priorityText, Due: ${task.dueDate})")
}
}

Output:

Task List (sorted by completion status, priority, and due date):
-----------------------------------------------------------------
[TODO] Fix bug #42 (Priority: High, Due: 2023-10-10)
[TODO] Complete project (Priority: High, Due: 2023-10-15)
[TODO] Team meeting (Priority: Medium, Due: 2023-10-09)
[TODO] Review code (Priority: Medium, Due: 2023-10-12)
[TODO] Update documentation (Priority: Low, Due: 2023-10-20)
[DONE] Weekly report (Priority: Medium, Due: 2023-10-08)

Summary

Kotlin provides powerful and flexible ways to order collections:

  • Natural ordering with sorted() and sortedDescending()
  • Property-based ordering with sortedBy() and sortedByDescending()
  • Multi-criteria ordering with sortedWith() and compareBy()
  • Reversing with reversed() and asReversed()
  • Random ordering with shuffled() and shuffle()

These ordering operations are invaluable when working with data collections and can greatly simplify your code when you need to present data in specific ways.

Exercises

  1. Create a list of your favorite books with title, author, and publication year. Sort them by author name, then by publication year.

  2. Implement a function that sorts a list of strings by their length, from shortest to longest.

  3. Create a playlist of songs (with title, artist, and duration) and sort them by duration in descending order.

  4. Write a function that sorts a list of numbers so that odd numbers come before even numbers, and each group is sorted in ascending order.

  5. Use shuffled() to create a function that randomly assigns students to project groups.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)