Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort List Using Different Keys

Extreme newbie here struggling to get a handle on all the different ways a list may be sorted. Suppose I have a list of objects and each object has several keys that might be used for sorting in different circumstances. I got some very useful information from this thread: Java Interface Comparator static compare, using Qwerky’s first example as a model created:

class Dog {
   private String name;
   private int age;
   private int height;
   private int weight;

   Dog(String n, int a, int b, int c){
      name = n;
      age = a;
      height = b;
      weight = c;
   }
   public String getDogName(){
      return name;
   }
   public int getDogAge(){
      return age;
   } 
   public int getDogHeight(){
      return height;
   }
   public int getDogWeight(){
      return weight;
   }
}

class DogComparator1 implements Comparator<Dog> {
   @Override
   public int compare(Dog d, Dog d1){
      return d.getDogAge() - d1.getDogAge();
   }
}
   class DogComparator2 implements Comparator<Dog> {
   @Override
   public int compare(Dog d, Dog d1){
      return d.getDogHeight() - d1.getDogHeight();
   }
}
   class DogComparator3 implements Comparator<Dog> { 
   @Override
   public int compare(Dog d, Dog d1){
      return d.getDogWeight() - d1.getDogWeight();
   }
}


public class Example{

   public static void main(String args[]){
      // Creat list of dog objects
      List<Dog> dogList = new ArrayList<>();

      // Add a buch of dogs to the list here
               .
               .

      // Create the Comparators
      DogComparator1 compare1 = new DogComparator1();
      DogComparator2 compare2 = new DogComparator2();
      DogComparator3 compare3 = new DogComparator3();


      // Sort the list using Comparators
      Collections.sort(list, compare1);  // Sort by age     
      Collections.sort(list, compare2);  // Sort by height
      Collections.sort(list, compare3);  // Sort by weight          
   }
}

But, this just doesn’t seem right. I think I want to pull the comparator definitions “inside” the Dog class to nicely encapsulate them. But, can’t figure out how to do it.

Am I on the right track? If so, help with the proper syntax would be greatly appreciated.

like image 883
Greg Valvo Avatar asked Jan 08 '23 22:01

Greg Valvo


2 Answers

You are definitely on the right track.

I would just add this inside your Dog class:

public static final Comparator<Dog> COMPARE_BY_AGE = new Comparator<Dog>() {
    @Override
    public int compare(Dog d, Dog d1) {
        return d.getDogAge() - d1.getDogAge();
    }
};

public static final Comparator<Dog> COMPARE_BY_HEIGHT = new Comparator<Dog>() {
    @Override
    public int compare(Dog d, Dog d1) {
        return d.getDogHeight() - d1.getDogHeight();
    }
};

public static final Comparator<Dog> COMPARE_BY_WEIGHT = new Comparator<Dog>() {
    @Override
    public int compare(Dog d, Dog d1) {
        return d.getDogWeight() - d1.getDogWeight();
    }
};

And then the usage is like follows:

    // Sort the list using Comparators
    Collections.sort(list, Dog.COMPARE_BY_AGE);  // Sort by age
    Collections.sort(list, Dog.COMPARE_BY_HEIGHT);  // Sort by height
    Collections.sort(list, Dog.COMPARE_BY_WEIGHT);  // Sort by weight
like image 70
vikingsteve Avatar answered Jan 11 '23 10:01

vikingsteve


I do not think it is a responsibility of the Dog class to know the different ways in which you can compare it. You can, however create those comparators as inner classes if that would feel more "encapsulated" for you (and even make this class private).

I.e. you could, inside Dog class, do this:

public class Dog {

(...)

    public Comparator<Dog> getAgeComparator() {
        return new AgeComparator();
    }

    private static class AgeComparator implements Comparator<Dog> {
       @Override
       public int compare(Dog d, Dog d1){
          return d.getDogAge() - d1.getDogAge();
       }
}

Or, instead of creating a getAgeComparator() method expose those comparators as:

public static final Comparator<Dog> AGE_COMPARATOR = new AgeComparator();

You could also just create the anonymous implementation there. The way you are doing this though is correct. I would not make Dog aware of how it can be compared. You could easily have those implementations live elsewhere, or even create anonymous class implementations on the fly if you do not reuse them. What you are trying to achieve is a wrong understanding of encapsulation.

You can create a default comparator though by making Dog class implement Comparable<Dog>:

public class Dog implements Comparable<Dog> {

    public int compareTo(Dog dog) {
        return AGE_COMPARATOR.compare(this, dog); // or inline comparison here
    }

    (...)
}
like image 28
theadam Avatar answered Jan 11 '23 12:01

theadam