Kotlin Comparator

Introduction

In Kotlin, the Comparator interface is used to define a custom ordering for objects. It is useful when you need to sort objects in a specific way that is not covered by their natural ordering defined by the Comparable interface. The Comparator interface allows you to create custom sorting logic and apply it to collections.

Table of Contents

  1. What is the Comparator Interface?
  2. Implementing the Comparator Interface
  3. Using the compare Method
  4. Examples of Comparator
  5. Real-World Use Case
  6. Conclusion

1. What is the Comparator Interface?

The Comparator interface in Kotlin is used to define a custom order for objects. It contains a single method, compare, which compares two objects and returns an integer based on their ordering.

Syntax

interface Comparator<T> {
    fun compare(o1: T, o2: T): Int
}

2. Implementing the Comparator Interface

To implement the Comparator interface, a class or an object needs to provide an implementation for the compare method. The compare method should return:

  • A negative integer if the first object is less than the second object.
  • Zero if the first object is equal to the second object.
  • A positive integer if the first object is greater than the second object.

Example

data class Person(val name: String, val age: Int)

class AgeComparator : Comparator<Person> {
    override fun compare(o1: Person, o2: Person): Int {
        return o1.age - o2.age
    }
}

3. Using the compare Method

The compare method is used to compare two objects and can be used for sorting collections.

Example

fun main() {
    val people = listOf(
        Person("Amit", 30),
        Person("Ravi", 25),
        Person("Priya", 35)
    )

    val sortedPeople = people.sortedWith(AgeComparator())
    sortedPeople.forEach { println(it) }
}

4. Examples of Comparator

Example 1: Sorting a List of Custom Objects by Multiple Properties

This example demonstrates sorting a list of custom objects using a comparator that sorts by multiple properties.

data class Student(val name: String, val grade: Double, val age: Int)

class GradeAndAgeComparator : Comparator<Student> {
    override fun compare(o1: Student, o2: Student): Int {
        return if (o1.grade == o2.grade) {
            o1.age - o2.age
        } else {
            o1.grade.compareTo(o2.grade)
        }
    }
}

fun main() {
    val students = listOf(
        Student("Rahul", 85.5, 20),
        Student("Anjali", 92.3, 22),
        Student("Vijay", 85.5, 19)
    )

    val sortedStudents = students.sortedWith(GradeAndAgeComparator())
    sortedStudents.forEach { println(it) }
}

Output:

Student(name=Vijay, grade=85.5, age=19)
Student(name=Rahul, grade=85.5, age=20)
Student(name=Anjali, grade=92.3, age=22)

Explanation:
This example sorts a list of Student objects based on their grades in ascending order, and if the grades are equal, it sorts by age.

Example 2: Custom Sorting with Comparator

This example demonstrates custom sorting using a comparator.

data class Book(val title: String, val price: Double)

fun main() {
    val books = listOf(
        Book("Kotlin for Beginners", 299.99),
        Book("Advanced Kotlin", 399.99),
        Book("Kotlin Cookbook", 349.99)
    )

    val sortedBooks = books.sortedWith(compareBy { it.price })
    sortedBooks.forEach { println(it) }
}

Output:

Book(title=Kotlin for Beginners, price=299.99)
Book(title=Kotlin Cookbook, price=349.99)
Book(title=Advanced Kotlin, price=399.99)

Explanation:
This example uses a custom comparator to sort a list of Book objects based on their prices.

Example 3: Sorting with Multiple Comparators

This example demonstrates sorting a list of employees first by department and then by salary.

data class Employee(val name: String, val department: String, val salary: Double)

val departmentComparator = compareBy<Employee> { it.department }
val salaryComparator = compareBy<Employee> { it.salary }

fun main() {
    val employees = listOf(
        Employee("Raj", "IT", 50000.0),
        Employee("Meena", "HR", 60000.0),
        Employee("Sandeep", "IT", 55000.0),
        Employee("Anita", "HR", 65000.0)
    )

    val sortedEmployees = employees.sortedWith(departmentComparator.then(salaryComparator))
    sortedEmployees.forEach { println(it) }
}

Output:

Employee(name=Meena, department=HR, salary=60000.0)
Employee(name=Anita, department=HR, salary=65000.0)
Employee(name=Raj, department=IT, salary=50000.0)
Employee(name=Sandeep, department=IT, salary=55000.0)

Explanation:
This example sorts a list of Employee objects first by department and then by salary within each department.

5. Real-World Use Case: Sorting Products in an E-commerce Application

In an e-commerce application, you might need to sort products based on various criteria such as price, rating, or popularity.

Example: Sorting Products by Price

data class Product(val name: String, val price: Double) : Comparable<Product> {
    override fun compareTo(other: Product): Int {
        return this.price.compareTo(other.price)
    }
}

fun main() {
    val products = listOf(
        Product("Laptop", 59999.99),
        Product("Smartphone", 29999.99),
        Product("Tablet", 19999.99)
    )

    val sortedProducts = products.sorted()
    sortedProducts.forEach { println(it) }
}

Output:

Product(name=Tablet, price=19999.99)
Product(name=Smartphone, price=29999.99)
Product(name=Laptop, price=59999.99)

Explanation:
This example sorts a list of Product objects based on their prices in ascending order.

Conclusion

The Comparator interface in Kotlin is used for defining custom orderings for objects. By implementing the compare method or using existing comparator functions, you can create flexible and reusable sorting logic. This is particularly useful for sorting collections and other data structures based on multiple criteria. 

Understanding how to implement and use the Comparator interface is essential for effective Kotlin programming, especially when dealing with ordered data.

Comments