How to Sort a List of Objects by Multiple Attributes in Java?

How to Sort a List of Objects by Multiple Attributes in Java?

Sorting a list of objects by multiple attributes is a common task in Java, especially when working with collections of custom objects. In this article, we will discuss various methods to achieve sorting by multiple attributes using techniques such as Comparator, Comparable, and Java Streams.

Understanding the Problem

Consider a scenario where you have a list of objects representing employees. Each employee has attributes such as name, age, and salary. You might want to sort the employees based on their age first and then by their salary if two employees have the same age.

Methods to Sort by Multiple Attributes

There are multiple ways to sort a list of objects by multiple attributes in Java. Let’s explore the three most commonly used methods:

1. Using Comparable Interface

The Comparable interface allows you to define the natural ordering of objects. This is helpful when you want to specify the default sorting logic for a custom class. However, Comparable supports only one sorting attribute at a time. To sort by multiple attributes, you need to implement custom logic within the compareTo method.

Code Example: Sorting by Age and then by Salary

import java.util.*;

class Employee implements Comparable {
    String name;
    int age;
    double salary;

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    @Override
    public int compareTo(Employee other) {
        // First, compare by age
        int ageComparison = Integer.compare(this.age, other.age);
        if (ageComparison != 0) {
            return ageComparison; // If ages are different, return the comparison result
        }
        // If ages are the same, compare by salary
        return Double.compare(this.salary, other.salary);
    }

    @Override
    public String toString() {
        return name + " (" + age + ", " + salary + ")";
    }

    public static void main(String[] args) {
        List employees = new ArrayList<>();
        employees.add(new Employee("John", 25, 50000));
        employees.add(new Employee("Alice", 30, 60000));
        employees.add(new Employee("Bob", 25, 55000));
        
        Collections.sort(employees); // Sort using compareTo method

        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
}

In this example, employees are sorted first by age and, if two employees have the same age, by salary.

2. Using Comparator Interface

The Comparator interface allows you to define custom sorting logic, separate from the class’s natural ordering. This is particularly useful when you want to sort by multiple attributes or define a sorting order that differs from the one specified by the Comparable interface.

Code Example: Sorting by Age and then by Salary using Comparator

import java.util.*;

class Employee {
    String name;
    int age;
    double salary;

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return name + " (" + age + ", " + salary + ")";
    }

    public static void main(String[] args) {
        List employees = new ArrayList<>();
        employees.add(new Employee("John", 25, 50000));
        employees.add(new Employee("Alice", 30, 60000));
        employees.add(new Employee("Bob", 25, 55000));

        // Sorting using Comparator
        employees.sort(Comparator.comparingInt((Employee e) -> e.age)
                .thenComparingDouble(e -> e.salary));

        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
}

Here, we use Comparator.comparingInt for age and thenComparingDouble for salary. This approach allows for flexible multi-criteria sorting.

3. Using Java Streams for Sorting

Java Streams provide a functional approach to working with collections. With Streams, you can sort objects based on multiple attributes by chaining comparator methods in a clean and readable way.

Code Example: Sorting by Age and then by Salary using Streams

import java.util.*;
import java.util.stream.*;

class Employee {
    String name;
    int age;
    double salary;

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return name + " (" + age + ", " + salary + ")";
    }

    public static void main(String[] args) {
        List employees = new ArrayList<>();
        employees.add(new Employee("John", 25, 50000));
        employees.add(new Employee("Alice", 30, 60000));
        employees.add(new Employee("Bob", 25, 55000));

        // Sorting using Streams
        List sortedEmployees = employees.stream()
                .sorted(Comparator.comparingInt((Employee e) -> e.age)
                        .thenComparingDouble(e -> e.salary))
                .collect(Collectors.toList());

        sortedEmployees.forEach(System.out::println);
    }
}

This method uses the stream() function to create a stream of employees, and then sorts them using the same Comparator logic as before. The result is collected into a new list.

Advanced Techniques: Custom Comparators and Chaining

When working with complex sorting criteria, you may need to create custom comparators or chain multiple comparators. The Comparator interface in Java allows you to do this effectively.

Code Example: Chaining Custom Comparators

import java.util.*;

class Employee {
    String name;
    int age;
    double salary;

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return name + " (" + age + ", " + salary + ")";
    }

    public static void main(String[] args) {
        List employees = new ArrayList<>();
        employees.add(new Employee("John", 25, 50000));
        employees.add(new Employee("Alice", 30, 60000));
        employees.add(new Employee("Bob", 25, 55000));

        Comparator comparator = Comparator
                .comparingInt((Employee e) -> e.age)
                .thenComparingDouble((Employee e) -> e.salary)
                .thenComparing((Employee e) -> e.name);

        // Sorting using custom comparator
        employees.sort(comparator);

        employees.forEach(System.out::println);
    }
}

In this example, we chain comparators to sort by age, then by salary, and finally by name. This approach allows for very fine-grained control over the sorting order.

Conclusion

Sorting a list of objects by multiple attributes in Java is a powerful feature that can be accomplished using Comparable, Comparator, or Java Streams. The method you choose depends on the complexity of your sorting criteria and your personal coding preferences.

© 2024 Tech Interview Guide. All rights reserved.

Please follow and like us:

Leave a Comment