Использование Comparable для нескольких динамических полей VO в java

У меня есть класс

public class StudentVO {
   int age;
   String name;  
}

Я использовал тот же класс в двух разных областях. В одном месте мне нужно сортировать по возрасту. В другом месте мне нужно сортировать по имени и в  в другом месте мне может понадобиться сортировка на основе как возраста, так и имени. Как я могу это сделать?  Если одно поле я может переопределить compareTo().

Можно ли это сделать?

Ответ 1

1) Вы должны написать два Comparator для сортировки по возрасту и имени отдельно, а затем использовать Коллекции. сортировки (List, компаратор). Что-то вроде этого:

class StudentVO {
  private String name;
  private int age;
  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;
  }
}

class AgeComparator implements Comparator<StudentVO> {

@Override
public int compare(StudentVO o1, StudentVO o2) {
    Integer age1 = o1.getAge();
    Integer age2 = o2.getAge();
    return age1.compareTo(age2);
  }

}

class NameComparator implements Comparator<StudentVO> {

  @Override
  public int compare(StudentVO o1, StudentVO o2) {
      return o1.getName().compareTo(o2.getName());
  }

}

И затем используйте их, Чтобы отсортировать на основе age:

Collections.sort(list,new AgeComparator());

для сортировки на основе name:

Collections.sort(list,new NameComparator());

2) Если вы считаете, что List of StudentVO имеет некоторый естественный порядок сортировки, скажем, предположим, что сортировка выполняется по age. Затем используйте Comparable для age и Comparator для name.

 class StudentVO implements Comparable<StudentVO>{
    private String name;
    private int age;
    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;
    }
    @Override
    public int compareTo(StudentVO o) {
        return ((Integer)getAge()).compareTo(o.getAge());
    }
}

class NameComparator implements Comparator<StudentVO> {

    @Override
    public int compare(StudentVO o1, StudentVO o2) {
        return o1.getName().compareTo(o2.getName());
    }

 }

И затем используйте их, Чтобы отсортировать на основе age:

Collections.sort(list);

для сортировки на основе name:

Collections.sort(list,new NameComparator());

Ответ 2

Вот фрагмент кода:

public class StudentNameComparator implements Comparator<StudentVO>{

@Override
public int compare(StudentVO s1, StudentVO s2) {

        //ascending order
        return s1.getName().compareTo(s2.getName());

        //descending order
        //return s2.getName().compareTo(s1.getName());
       }
}

Согласно вашему вопросу, он также будет работать, когда значения указанного поля будут изменены. Вы должны помнить только для вызова метода sort с этим компаратором.

Ответ 3

В java у вас есть два основных способа сравнения объектов. Первым для самого класса является реализация интерфейса Comparable, который будет означать только одну реализацию. Второй способ состоит в том, чтобы классы реализовывали Comparator интерфейс. Таким образом, вы можете иметь несколько компараторов для одного и того же класса.

Это означает, что вы могли бы определить, например, 3 сопоставителя diffenrent в вашем классе StudentVo: один, который сравнивается только с именем, другой, который сравнивает возрастные и последние, которые оба свойства.

В вашем приложении вы используете реализацию, которая вам подходит, на основе того, что вы хотите сравнить. В одном месте вы будете сравнивать студентов по возрасту Collections.sort(myStudents, новый CompareStudentOnAge()). В другом месте вы используете другую реализацию.

Вы можете найти некоторые пояснения в этом сообщении в блоге: http://javarevisited.blogspot.fr/2011/06/comparator-and-comparable-in-java.html

Ответ 4

Мне недавно пришлось решить эту проблему. Не уверен, что это точно такой же сценарий, как ваш, но мне пришлось написать сортировку в памяти для нулевого или большего количества столбцов сетки, ручную работу над условиями OOM и т.д., Потому что моя проблема была очень ограниченной по охвату.

Я написал компаратор для каждого столбца и компаратор, который взял список компараторов. Когда я определил, какие столбцы нужно сортировать и в каком порядке, я добавил экземпляр соответствующего компаратора в список компараторов. Затем используйте цепной компаратор для выполнения фактического сортировки.

public class MyObject
{
    private String name;
    private int age;
    private Date registered;
}

Итак, что-то вроде этого для каждого компаратора:

public class NameComparator
    implements Comparator<MyObject>
{
    public int compare(MyObject o1, MyObject o2)
    {
        return o1.getName().compareTo(o2.getName);
    }
}

Это для цепного компаратора:

public class ChainedComparator
    implements Comparator<MyObject>
{
    public int compare(MyObject o1, MyObject o2) {
        for(Comparator<MyObject> comparator : comparators) {
            int result = comparator.compare(o1,o2);
            if(result != 0) {
                return result;
            }
        }
        return 0;
    }
}
    private List<Comparator<MyObject>> comparators = new ArrayList<>();
}

Слева к вашему воображению анализируется сортировка и построение цепного компаратора. Я на самом деле сделал это немного сложнее, потому что я также включил направление, которое я реализовал, заменив порядок параметров в вызове субкомпозитора в прикованном компараторе по мере необходимости.

Ответ 5

Новый подход для этого в java-8 см. Сравнение компаратора # и Компаратор # thenComparing. Все, что вам нужно, это предоставить ссылку на выражение lamda или метод метода Stream#sorted() или List#sort().

Например, сортировка по одному полю:

List<StudentVO> students = Arrays.asList(
        new StudentVO(20,"Bob"),
        new StudentVO(19, "Jane")
);
// sort by age
students.stream()
        .sorted(Comparator.comparing(StudentVO::getAge))
        .forEach(System.out::println);
// [StudentVO{age=19, name='Jane'},StudentVO{age=20, name='Bob'}]
// sort by name
students.stream()
        .sorted(Comparator.comparing(StudentVO::getName))
        .forEach(System.out::println);
// [StudentVO{age=20, name='Bob'}, StudentVO{age=19, name='Jane'}]

Сортировка по нескольким полям:

List<StudentVO> students = Arrays.asList(
        new StudentVO(20,"Bob"),
        new StudentVO(19, "Jane"),
        new StudentVO(21,"Bob")
);
// by age and then by name
students.stream()
        .sorted(Comparator
                .comparing(StudentVO::getAge)
                .thenComparing(StudentVO::getName)
        ).forEach(System.out::println);
// [StudentVO{age=19, name='Jane'}, StudentVO{age=20, name='Bob'}, StudentVO{age=21, name='Bob'}]
// by name an then by age
students.stream()
        .sorted(Comparator
                .comparing(StudentVO::getName)
                .thenComparing(StudentVO::getAge)
        ).forEach(System.out::println);
// [StudentVO{age=20, name='Bob'}, StudentVO{age=21, name='Bob'}, StudentVO{age=19, name='Jane'}]