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

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

public class StudentVO {
   int age;
   String name;  
}

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

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


person samba    schedule 25.04.2013    source источник


Ответы (7)


1) Необходимо написать два компаратора для сортировки по возрасту и имени отдельно , а затем используйте Collections.sort(Список,Сравнение). Что-то вроде этого:

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 из 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());
person AllTooSir    schedule 25.04.2013
comment
хороший .... но у меня другая проблема ... мои атрибуты динамические ... основаны на пользователе ... так что могу ли я создать класс компаратора во время выполнения в соответствии с атрибутом пользователя? - person H Raval; 22.12.2015
comment
@HRaval Я не совсем понял, что вы подразумеваете под динамическим атрибутом, тем не менее, можете ли вы проверить, поможет ли вам класс Commons Apache «CompareToBuilder»? - person AllTooSir; 22.12.2015

Для этого есть новый подход в java-8 см. Comparator#comparing и Comparator#thenComparing. Все, что вам нужно, это предоставить ссылку на лямда-выражение/метод либо для метода 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'}]
person Anton Balaniuc    schedule 08.08.2017

Недавно мне тоже пришлось решать эту проблему. Не уверен, что это точно такой же сценарий, как у вас, но мне пришлось написать сортировку в памяти для нуля или более столбцов сетки, ручное управление условиями 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<>();
}

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

person colin    schedule 30.09.2014

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

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 с этим компаратором.

person Kamil Chaber    schedule 25.04.2013

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

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

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

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

person Quentin Proust    schedule 25.04.2013

Подход Антона неплох. Я использую этот:

1- Для сортировки только по возрасту:

Collections.sort( studentList, Comparator.comparingInt( student -> student.getAge() ) );

2- Для имени:

Collections.sort( studentList, Comparator.comparing( student -> student.getName() ) ); 

3- Комбинация:

Collections.sort( studentList, Comparator.comparing( student -> student.getName() ).thenComparingInt( student -> student.getAge() ) ); 
person Mohammad Eghlima    schedule 16.12.2019

Вы можете каскадировать компараторы с thenComparing:

List<File> files = new ArrayList();
Collections.sort(files,

        new Comparator<File>() {
            public int compare(File file1, File file2) {
                return file2.getName()
                        .compareTo(file1.getName());
            }
        }.thenComparing(
                new Comparator<File>() {
                    public int compare(File file1, File file2) {
                        return Long.valueOf(file2.getPath().length())
                                .compareTo(Long.valueOf(file1.getPath().length()));
                    }
                }
        )

);
// Collections.reverse(list);

https://www.eovao.com/en/a/sort%20elements%20java/4/how-to-sort-objects-in-java---multiple-comparison-sort-list< /а>

person oat    schedule 22.04.2020