How to use Java comparator properly?

2020-02-06 07:02发布

问题:

If I have the following class:

public class Employee {
    private int empId;
    private String name;
    private int age;

    public Employee(int empId, String name, int age) {
        // set values on attributes
    }
    // getters & setters
}

How can I use comparator that compares by name, then age, then id?

回答1:

You need to implement it so that it orders by preferred elements. That is, you need to compare by name, then if that comparison is equal, compare by age, etc. An example is listed below:

public class EmployeeComparator implements Comparator<Employee> {

  @Override
  public int compare(Employee e1, Employee e2) {
    int nameDiff = e1.getName().compareTo(e2.getName());

    if(nameDiff != 0) {
      return nameDiff;
    }

    int ageDiff = e1.getAge() - e2.getAge();

    if(ageDiff != 0) {
      return ageDiff;
    }

    int idDiff = e1.getEmpId() - e2.getEmpId();

    return idDiff;
  }
}


回答2:

Update

Came across this a moment ago: How to compare objects by multiple fields One of the answers linked to ComparatorChain which will invoke multiple comparators in sequence until a non-zero result is received from a comparator or all comparators are invoked. This should probably be your preferred solution.


Perhaps this (untested) implementation of Comparator#compare() will do the trick.

int compare(Employee e, Employee f)
{
    int val = e.name.compareTo(f.name);

    if(val == 0)
    {
        val = e.age - f.age;

        if(val == 0)
        {
            val = e.empId - f.empId;
        }
    }

    return val;
}


回答3:

You can also implement the Comparable Interface in your class.

for example, something like this:

public class Employee implements Comparable<Employee>{
    private int empId;
    private String name;
    private int age;

    public Employee(int empId, String name, int age) {
            // set values on attributes

    }
    // getters & setters

    public int compareTo(Employee o) {
        int ret = this.name.compareTo(o.name);
        if(ret == 0)
            ret = this.age - o.age;
        if(ret == 0)
            ret = this.empId - o.empId;

        return ret;
    }
}

so you don't have to implement a extra class to compare your Employees.



回答4:

Implement it

public class Employee {
    private int empId;
    private String name;
    private int age;
    /**
     * @param empId
     * @param name
     * @param age
     */
    public Employee(int empId, String name, int age) {
        super();
        this.empId = empId;
        this.name  = name;
        this.age   = age;
    }
    /**
     * 
     */
    public Employee() {
        super();
        // TODO Auto-generated constructor stub
    }


    public int getEmpId() {
        return empId;
    }
    public void setEmpId(int empId) {
        this.empId = empId;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    //Compare by name, age and then id
    public static Comparator<Employee> COMPARE_EMPLOYEE = new Comparator<Employee>() {
        public int compare(Employee one, Employee other) {
            //Compare Name
            if (one.getName().compareToIgnoreCase(other.getName()) == 0) {
                //Compare age
                if((one.getAge() - other.getAge()) == 0) {
                    // Now check with id is useless
                    // So directly return result of compare by id
                    return one.getEmpId() - other.getEmpId();
                } else { //If age Not equal
                    return one.getAge() - other.getAge();
                }
            } else { //If name not equal
                return one.getName().compareToIgnoreCase(other.getName());
            }
        }
    };
}

Use :

List<Employee> contacts = new ArrayList<Employee>();
//Fill it.

//Sort by address.
Collections.sort(contacts, Employee.COMPARE_EMPLOYEE);

Read Sorting an ArrayList of Contacts , this must help you and you will get more ideas and different different types of use of Comparator.



回答5:

guava ComparisonChain:

    List<Employee> list = new ArrayList<Employee>();
    //...
    Collections.sort(list, new Comparator<Employee>(){    
         @Override 
         public int compare(Employee e1, Employee e2) {
            return ComparisonChain.start()  
                 .compare(e1.empId, e2.empId)  
                 .compare(e1.name, e2.name) 
                 .compare(e1.age, e2.age).result(); 
    }});


回答6:

Use this:

public class Test 
{
    public static void main(String[] args) 
    {
        Employee emp1 = new Employee(2, "Tom", 20);
        Employee emp2 = new Employee(1, "Tom", 20);
        Employee emp3 = new Employee(3, "Hank", 21);

        List<Employee> list = new ArrayList<>();

        list.add(emp1);
        list.add(emp2);
        list.add(emp3);

        Collections.sort(list, new Employee().new MyComparator());

        System.out.println(list);
    }
}

class Employee 
{
    private int empId;
    private String name;
    private int age;

    public Employee()
    {}

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

    class MyComparator implements Comparator<Employee>
    {
        @Override
        public int compare(Employee e1, Employee e2) 
        {
            if(e1.name.compareTo(e2.name) == 0)
            {
                if(((Integer)e1.age).compareTo(e2.age) == 0)
                {
                    return ((Integer)e1.empId).compareTo(e2.empId);
                }
                else
                {
                    return ((Integer)e1.age).compareTo(e2.age);
                }
            }
            return e1.name.compareTo(e2.name);
        }
    }

    @Override
    public String toString() 
    {
        return "Employee [empId=" + empId + ", name=" + name + ", age=" + age + "]";
    }
}


回答7:

The Comparator interface defines two methods: compare() and equals().

The compare() method, compares two elements for order: int compare(Object obj1, Object obj2)

obj1 and obj2 are the objects to be compared. This method returns zero if the objects are equal. It returns a positive value if obj1 is greater than obj2. Otherwise, a negative value is returned.

By overriding compare(), you can alter the way that objects are ordered. For example, to sort in a reverse order, you can create a comparator that reverses the outcome of a comparison.

The equals() method, tests whether an object equals the invoking comparator: boolean equals(Object obj)

obj is the object to be tested for equality. The method returns true if obj and the invoking object are both Comparator objects and use the same ordering. Otherwise, it returns false.

Example:

import java.util.*;

class Dog implements Comparator<Dog>, Comparable<Dog> {
   private String name;
   private int age;
   Dog() {
   }

   Dog(String n, int a) {
      name = n;
      age = a;
   }

   public String getDogName() {
      return name;
   }

   public int getDogAge() {
      return age;
   }

   // Overriding the compareTo method
   public int compareTo(Dog d) {
      return (this.name).compareTo(d.name);
   }

   // Overriding the compare method to sort the age 
   public int compare(Dog d, Dog d1) {
      return d.age - d1.age;
   }
}

public class Example {

   public static void main(String args[]) {
      // Takes a list o Dog objects
      List<Dog> list = new ArrayList<Dog>();

      list.add(new Dog("Shaggy", 3));
      list.add(new Dog("Lacy", 2));
      list.add(new Dog("Roger", 10));
      list.add(new Dog("Tommy", 4));
      list.add(new Dog("Tammy", 1));
      Collections.sort(list);   // Sorts the array list

      for(Dog a: list)   // printing the sorted list of names
         System.out.print(a.getDogName() + ", ");

      // Sorts the array list using comparator
      Collections.sort(list, new Dog());
      System.out.println(" ");

      for(Dog a: list)   // printing the sorted list of ages
         System.out.print(a.getDogName() +"  : "+ a.getDogAge() + ", ");
   }
}

Check it out for more Java Comparator examples.