java 在java中对VO的多个动态字段使用Comparable

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16206629/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 22:12:48  来源:igfitidea点击:

Using Comparable for multiple dynamic fields of VO in java

javacomparatorcomparable

提问by samba

I have a class

我有一堂课

public class StudentVO {
   int age;
   String name;  
}

I used the same class in two different areas. At one place i need to sort based on the age. In another place I need to sort based on the name and in another place i may need sorting based on both age and name. How can I do this? If one field I can override compareTo().

我在两个不同的领域使用了同一个类。在一个地方,我需要根据年龄进行排序。在另一个地方,我需要根据姓名进行排序,而在另一个地方,我可能需要根据年龄和姓名进行排序。我怎样才能做到这一点?如果一个字段我可以覆盖compareTo().

Is it possible to do this?

是否有可能做到这一点?

回答by NINCOMPOOP

1)You should write two Comparatorfor sorting on age and name separately, and then use the Collections.sort(List,Comparator). Something like this:

1)你应该写两个Comparator 分别按年龄和姓名排序,然后使用Collections.sort(List,Comparator)。像这样的东西:

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

}

And then use them, To sort based on age:

然后使用它们,基于以下进行排序age

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

to sort based on name:

排序基于name

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

2) If you think that the Listof StudentVOhas some natural order of sorting, say suppose sort by age. Then, use Comparablefor ageand Comparatorfor name.

2) 如果您认为ListofStudentVO具有某种自然排序顺序,请假设 sort by age。然后,使用ComparableforageComparatorfor 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());
    }

 }

And then use them, To sort based on age:

然后使用它们,基于以下进行排序age

Collections.sort(list);

to sort based on name:

排序基于name

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

回答by Anton Balaniuc

There is new approach for this in java-8see Comparator#comparingand Comparator#thenComparing. All you need is to provide a lamda expression/method reference either to Stream#sorted()or List#sort()method.

java-8请参阅Comparator#comparingComparator#thenComparing对此有新的方法。您所需要的只是提供对Stream#sorted()List#sort()方法的 lamda 表达式/方法引用。

For example sorting by one field:

例如按一个字段排序:

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'}]

Sorting by a few fields:

按几个字段排序:

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'}]

回答by colin

I recently had to solve this problem, too. Not sure if this is exactly the same scenario as yours, but I had to write an in-memory sort for zero or more columns of a grid, handwaving over OOM conditions, etc, because my problem was very limited in scope.

我最近也不得不解决这个问题。不确定这是否与您的场景完全相同,但我必须为网格的零列或更多列编写内存排序,切换 OOM 条件等,因为我的问题范围非常有限。

I wrote a comparator for each column and a comparator that took a list of comparators. As I identified which columns needed to be sorted and in what order, I added an instance of the corresponding comparator to the list of comparators. Then, use the chained comparator to execute the actual sort.

我为每一列编写了一个比较器和一个比较器列表的比较器。当我确定哪些列需要排序以及按什么顺序排序时,我将相应比较器的实例添加到比较器列表中。然后,使用链式比较器执行实际排序。

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

So, something like this for each comparator:

因此,对于每个比较器,类似这样的事情:

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

This for the chained comparator:

这对于链式比较器:

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

Left to your imagination is parsing the sorts and building the chained comparator. I actually made this a bit more complicated because I also incorporated a direction which I implemented by swapping the order of parameters in the call to the sub-comparator in the chained comparator as needed.

留给您的想象力是解析排序并构建链接的比较器。我实际上让这更复杂了一点,因为我还合并了一个方向,我通过根据需要交换调用中的参数顺序到链式比较器中的子比较器来实现。

回答by Kamil Chaber

Here is the code snippet:

这是代码片段:

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

According to your question, it will also work when values of specified field will change. You have only to remember to call sortmethod with this comparator.

根据您的问题,当指定字段的值发生变化时,它也会起作用。你只需要记住sort用这个比较器调用方法。

回答by Quentin Proust

In java, you have two main way to compare objects. The first is for the class itself to implement the Comparableinterface which will mean only one implementations. The second is to have classes implements Comparatorinterface. This way, you can have multiple comparators for the same class.

在 Java 中,您有两种主要的方法来比较对象。第一个是类本身实现Comparable接口,这意味着只有一个实现。第二个是让类实现Comparator接口。这样,您可以为同一个类使用多个比较器。

This mean that you could define for exemple 3 diffenrent Comparators on your StudentVo class : one that compare only on the name, another that compare the ages and the last one that both properties.

这意味着您可以在 StudentVo 类上定义例如 3 个不同的比较器:一个只比较名称,另一个比较年龄,最后一个比较两个属性。

In your application, you use the implementation that suit you need based on what you want to compare. In one place, you will compare students on age Collections.sort(myStudents , new CompareStudentOnAge()). In another place, you use another implementation.

在您的应用程序中,您可以根据要比较的内容使用适合您的实现。在一处,您将比较年龄 Collections.sort(myStudents, new CompareStudentOnAge()) 上的学生。在另一个地方,您使用另一个实现。

You can find some explanations in this blog post : http://javarevisited.blogspot.fr/2011/06/comparator-and-comparable-in-java.html

您可以在这篇博文中找到一些解释:http: //javarevisited.blogspot.fr/2011/06/comparator-and-comparable-in-java.html

回答by Mohammad Eghlima

Anton's approach is quite good. I use this one:

安东的做法相当不错。我用这个:

1- For sorting only by age:

1- 仅按年龄排序:

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

2- For name:

2- 对于名称:

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

3- Combination:

3-组合:

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

回答by oat

You can cascade the comparators with thenComparing:

您可以使用 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

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