简体   繁体   中英

java comparator, how to sort by integer?

Im trying to learn comparator in java and I have found this great example online, my question is how would this code be changed so that the pet names are ordered by age and in descending order so that the oldest is first and youngest is last?

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() + ", ");
}
}

Simply changing

public int compare(Dog d, Dog d1) {
  return d.age - d1.age;
}

to

public int compare(Dog d, Dog d1) {
  return d1.age - d.age;
}

should sort them in the reverse order of age if that is what you are looking for.

Update:

@Arian is right in his comments, one of the accepted ways of declaring a comparator for a dog would be where you declare it as a public static final field in the class itself.

class Dog implements Comparable<Dog> {
    private String name;
    private int age;

    public static final Comparator<Dog> DESCENDING_COMPARATOR = new Comparator<Dog>() {
        // Overriding the compare method to sort the age
        public int compare(Dog d, Dog d1) {
            return d.age - d1.age;
        }
    };

    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);
    }

}

You could then use it any where in your code where you would like to compare dogs as follows:

// Sorts the array list using comparator
Collections.sort(list, Dog.DESCENDING_COMPARATOR);

Another important thing to remember when implementing Comparable is that it is important that compareTo performs consistently with equals. Although it is not required, failing to do so could result in strange behaviour on some collections such as some implementations of Sets. See this post for more information on sound principles of implementing compareTo.

Update 2: Chris is right, this code is susceptible to overflows for large negative values of age. The correct way to implement this in Java 7 and up would be Integer.compare(d.age, d1.age) instead of d.age - d1.age .

Update 3: With Java 8, your Comparator could be written a lot more succinctly as:

public static final Comparator<Dog> DESCENDING_COMPARATOR = 
    Comparator.comparing(Dog::getDogAge).reversed();

The syntax for Collections.sort stays the same, but compare can be written as

public int compare(Dog d, Dog d1) {
    return DESCENDING_COMPARATOR.compare(d, d1);
}

Just replace:

return d.age - d1.age;

By:

return ((Integer)d.age).compareTo(d1.age);

Or invert to reverse the list:

return ((Integer)d1.age).compareTo(d.age);

EDIT:

Fixed the "memory problem".
Indeed, the better solution is change the age field in the Dog class to Integer , because there many benefits, like the null possibility...

public class DogAgeComparator implements Comparator<Dog> {
    public int compare(Dog o1, Dog o2) {
        return Integer.compare(o1.getAge(), o2.getId());
    }
}

从Java 8开始,您可以使用:

Comparator.comparingInt(Dog::getDogAge).reversed();

One simple way is

Comparator<Dog> ageAscendingComp = ...;
Comparator<Dog> ageDescendingComp = Collections.reverseOrder(ageAscendingComp);
// then call the sort method

On a side note, Dog should really not implement Comparator . It means you have to do strange things like

Collections.sort(myList, new Dog("Rex", 4));
// ^-- why is a new dog being made? What are we even sorting by?!
Collections.sort(myList, myList.get(0));
// ^-- or perhaps more confusingly

Rather you should make Compartors as separate classes.

eg.

public class DogAgeComparator implments Comparator<Dog> {
    public int compareTo(Dog d1, Dog d2) {
        return d1.getAge() - d2.getAge();
    }
}

This has the added benefit that you can use the name of the class to say how the Comparator will sort the list. eg.

Collections.sort(someDogs, new DogNameComparator());
// now in name ascending order

Collections.sort(someDogs, Collections.reverseOrder(new DogAgeComparator()));
// now in age descending order

You should also not not have Dog implement Comparable . The Comparable interface is used to denote that there is some inherent and natural way to order these objects (such as for numbers and strings). Now this is not the case for Dog objects as sometimes you may wish to sort by age and sometimes you may wish to sort by name.

If you have access to the Java 8 Comparable API, Comparable.comparingToInt() may be of use. (See Java 8 Comparable Documentation ).

For example, a Comparator<Dog> to sort Dog instances descending by age could be created with the following:

Comparable.comparingToInt(Dog::getDogAge).reversed();

The function take a lambda mapping T to Integer , and creates an ascending comparator. The chained function .reversed() turns the ascending comparator into a descending comparator.

Note: while this may not be useful for most versions of Android out there, I came across this question while searching for similar information for a non-Android Java application. I thought it might be useful to others in the same spot to see what I ended up settling on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM