【问题标题】:Sorting a collection of objects [duplicate]对对象集合进行排序[重复]
【发布时间】:2010-11-15 10:03:00
【问题描述】:

如果我有一个简单的字符串列表:

List<String> stringList = new ArrayList<String>();

我可以使用:

Collections.sort(stringList);

但假设我有一个 Person 类:

public class Person
{
   private String name;
   private Integer age;
   private String country;
}

还有一个列表:

List<Person> personList = new ArrayList<Person>();

我有时想按名称、有时按年龄、有时按国家/地区对其进行排序。

最简单的方法是什么?

我知道我可以实现 Comparable 接口,但这似乎限制了我按一个特定属性对其进行排序。

【问题讨论】:

  • 也许你不应该在标题中使用形容词“复合”,因为它听起来像复合模式......

标签: java sorting collections


【解决方案1】:

Collections.sort 可以使用自定义比较器调用。并且可以实现该比较器以允许以不同的排序顺序进行排序。这是一个示例(对于您的 Person 模型 - 年龄为整数):

public class FlexiblePersonComparator implements Comparator<Person> {
  public enum Order {Name, Age, Country}

  private Order sortingBy = Name;

  @Override
  public int compare(Person person1, Person person2) {
    switch(sortingBy) {
      case Name: return person1.name.compareTo(person2.name);
      case Age: return person1.age.compareTo(person2.age);
      case Country: return person1.country.compareTo(person2.country);
    }
    throw new RuntimeException("Practically unreachable code, can't be thrown");
  }

  public void setSortingBy(Order sortBy) {
    this.sortingBy = sortingBy;
  }
}

然后你就这样使用它(假设 people 是一个字段):

public void sortPersonsBy(FlexiblePersonComparator.Order sortingBy) {
  List<Person> persons = this.persons;  // useless line, just for clarification
  FlexiblePersonComparator comparator = new FlexiblePersonComparator();
  comparator.setSortingBy(sortingBy);
  Collections.sort(persons, comparator); // now we have a sorted list
}

【讨论】:

  • +1 我喜欢灵活比较器的想法
  • 你也可以在构造函数中传递sortingBy参数。
  • Answer by @Yishai in this post 演示了使用比较器链优雅地使用枚举进行自定义排序和分组排序(多个参数)。
  • 这应该被接受的答案
【解决方案2】:

实现Comparator 接口(每个不同的排序顺序一次)并使用将 Comparator 作为附加参数的Collections.sort() 方法。

【讨论】:

    【解决方案3】:

    感谢响应者。为了他人的利益,我想提供一个完整的示例。

    解决方案是创建以下附加类:

    public class NameComparator implements Comparator<Person>
    {
        public int compare(Person o1, Person o2)
        {
           return o1.getName().compareTo(o2.getName());
       }
    }
    
    public class AgeComparator implements Comparator<Person>
    {
        public int compare(Person o1, Person o2)
        {
            return o1.getAge().compareTo(o2.getAge());
        }
    }
    
    public class CountryComparator implements Comparator<Person>
    {
        public int compare(Person o1, Person o2)
        {
            return o1.getCountry().compareTo(o2.getCountry());
        }
    }
    

    然后可以像这样对列表进行排序:

    Collections.sort(personList, new NameComparator());
    Collections.sort(personList, new AgeComparator());
    Collections.sort(personList, new CountryComparator());
    

    【讨论】:

      【解决方案4】:

      Java 8 的做法是使用List.sort,如下所示:

      personList.sort(Comparator.comparing(Person::getName));
      

      在他对here 的回答中引用Stuart Marks

      这是List.sort(cmp) 扩展方法相对于Collections.sort(list, cmp) 的一大优势。看起来这只是一个小的语法优势,可以写成myList.sort(cmp) 而不是Collections.sort(myList, cmp)。不同之处在于myList.sort(cmp) 作为接口扩展方法,可以被特定的List 实现覆盖。例如,ArrayList.sort(cmp) 使用 Arrays.sort() 对列表进行就地排序,而默认实现实现了旧的 copyout-sort-copyback 技术。

      【讨论】:

        【解决方案5】:

        您也可以使用 apache commons beanutils 中的 BeanComparator,如下所示:

        Collections.sort(personList, new BeanComparator("name"));
        

        【讨论】:

        • 不错的一个。以前没见过
        【解决方案6】:

        实现 3 种不同类型的比较器。

        您可以将比较器添加到排序命令。您定义的比较器将按名称、年龄或其他任何内容对元素进行排序。

        Collections.sort(list, new Comparator() {
        
                public int compare(Object arg0, Object arg1) {
                    if (!(arg0 instanceof Person)) {
                        return -1;
                    }
                    if (!(arg1 instanceof Person)) {
                        return -1;
                    }
        
                    Person pers0 = (Person)arg0;
                    Person pers1 = (Person)arg1;
        
        
                    // COMPARE NOW WHAT YOU WANT
                    // Thanks to Steve Kuo for your comment!
                    return pers0.getAge() - pers1.getAge();
                }
            });
        

        【讨论】:

        • 为什么不对比较器使用参数类型?
        • 因为我来自 1.4 ;)
        • 你可以只返回 pers0.getAge() - pers1.getAge()。这适用于三种情况( 和 ==)。
        【解决方案7】:

        可以使用第二个参数调用 Collections.sort 方法,该参数是要使用的比较器。 创建 3 个比较器,并在适当的时候使用您想要的一个。

        Collections.sort(list , new Comparator() {
                public int compare(Object o1, Object o2) {
                  ...
                }
              });
        

        【讨论】:

        • awwww ... Comparator ... 合成糖很好吃!
        • 是的,我也这么认为。应该是Collections.sort(Person , new Comparator&lt;Person&gt;() {
        【解决方案8】:

        我问了very similar question(关于搜索而不是排序),也许有一些有用的信息(我最终使用了实现Comparatorenum,所以我将enum 值作为比较器选择器传递) .

        【讨论】:

          【解决方案9】:

          使用 lambdaj (http://code.google.com/p/lambdaj/),您可以通过以下方式实现您的要求:

          排序(personList, on(Person.class).getName());

          排序(personList, on(Person.class).getAge());

          sort(personList, on(Person.class).getCountry());

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多