Welcome to our exploration of sorted maps using custom classes and comparators in Kotlin. In today's lesson, we'll learn how to use custom data classes as keys in sorted maps. This approach enhances data organization and access. With the addition of comparators, we can dictate the order in such maps.
A sorted map is a collection with its keys always in order. This arrangement makes operations like searching for keys within a range more efficient. In Kotlin, we often use the sortedMapOf
function or TreeMap
from Java's standard library for sorted maps:
Kotlin1import java.util.TreeMap 2 3fun main() { 4 val sMap = sortedMapOf("a" to 1, "b" to 2, "c" to 3) 5 6 println(sMap) // Outputs {a=1, b=2, c=3} 7}
Custom classes enable us to create objects that fit our data — for instance, a Person
data class for employee information or a Book
data class for a library database. In Kotlin, data classes provide a concise and idiomatic approach to creating such objects.
Consider this simple data class, for example:
Kotlin1data class Person(val name: String, val age: Int) 2 3fun main() { 4 val person = Person(name = "John Doe", age = 30) 5 println(person.name) // Outputs "John Doe" 6 println(person.age) // Outputs 30 7}
Using custom classes as map keys helps organize complex multivariate keys in a sorted map. Consider the following example using the Person
data class as a key in a sorted map. However, this will not work yet without a comparator.
Kotlin1import java.util.TreeMap 2 3data class Person(val name: String, val age: Int) 4 5fun main() { 6 val people = TreeMap<Person, String>() 7 8 val john = Person("John", 30) 9 val alice = Person("Alice", 25) 10 11 people[john] = "Programmer" 12 people[alice] = "Designer" 13}
In this code, John is assigned the value "Programmer"
, and Alice is assigned the value "Designer."
However, this code will produce an error because TreeMap
requires a way to compare the Person
objects to maintain its order.
Kotlin uses a comparator to determine the order of two keys. To make this comparison, we implement the Comparable
interface or use a custom Comparator
. Without these methods, TreeMap
can't compare its Person
class keys. Here’s how to modify the Person
class to use a comparator:
Kotlin1import java.util.TreeMap 2 3data class Person(val name: String, val age: Int) : Comparable<Person> { 4 override fun compareTo(other: Person): Int { 5 return compareValuesBy(this, other, { it.age }, { it.name }) 6 } 7} 8 9fun main() { 10 val people = TreeMap<Person, String>() 11 12 val john = Person("John", 30) 13 val alice = Person("Alice", 25) 14 15 people[john] = "Programmer" 16 people[alice] = "Designer" 17 18 for ((person, profession) in people) { 19 println("${person.name} is a $profession") 20 } 21 // Output: 22 // Alice is a Designer 23 // John is a Programmer 24}
In the code above, we implement the compareTo
method using compareValuesBy
to ensure that Person
objects are initially sorted by age and, if ages are the same, then by name. The data class automatically provides equals
and hashCode
implementations, ensuring consistency in collections like TreeMap
.
We've explored how to use custom data classes as keys in sorted maps and how comparators work in this context using Kotlin's Comparable
interface. Now, prepare for some hands-on exercises to reinforce these concepts.