使用比较器降序排序(用户定义的类)


77

我想使用比较器按降序对对象进行排序。

class Person {
 private int age;
}

在这里,我想对一个Person对象数组进行排序。

我怎样才能做到这一点?

Answers:


116

您可以通过覆盖compare()方法的方式来进行用户定义类的降序排序,

Collections.sort(unsortedList,new Comparator<Person>() {
    @Override
    public int compare(Person a, Person b) {
        return b.getName().compareTo(a.getName());
    }
});

通过使用Collection.reverse()用户Prince其评论中提到的降序进行排序。

您可以像这样进行升序排序,

Collections.sort(unsortedList,new Comparator<Person>() {
    @Override
    public int compare(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }
});

我们用简洁的Lambda表达式(从Java 8开始)替换上面的代码:

Collections.sort(personList, (Person a, Person b) -> b.getName().compareTo(a.getName()));

从Java 8开始,List具有sort()方法,该方法将Comparator作为参数(更简洁):

personList.sort((a,b)->b.getName().compareTo(a.getName()));

在这里ab通过lambda表达式推断为Person类型。


23
或者,您可以仅使用Collections.reverseOrder(...)降序排序。
王子

1
@Prince没有这种做法的风扇,它迫使我看看原始的方法,看看事情是如何分类到开始(非反转。)
b1nary.atr0phy

1
值得一提的compareToIgnoreCase是,比较String对象时也很方便,我经常使用它,而不仅仅是compareTo
Mark Keen

像魅力一样工作!谢谢。

69

对于它的价值,这是我的标准答案。这里唯一的新内容是使用Collections.reverseOrder()。另外,它把所有建议都放在一个例子中:

/*
**  Use the Collections API to sort a List for you.
**
**  When your class has a "natural" sort order you can implement
**  the Comparable interface.
**
**  You can use an alternate sort order when you implement
**  a Comparator for your class.
*/
import java.util.*;

public class Person implements Comparable<Person>
{
    String name;
    int age;

    public Person(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

    public int getAge()
    {
        return age;
    }

    public String toString()
    {
        return name + " : " + age;
    }

    /*
    **  Implement the natural order for this class
    */
    public int compareTo(Person p)
    {
        return getName().compareTo(p.getName());
    }

    static class AgeComparator implements Comparator<Person>
    {
        public int compare(Person p1, Person p2)
        {
            int age1 = p1.getAge();
            int age2 = p2.getAge();

            if (age1 == age2)
                return 0;
            else if (age1 > age2)
                return 1;
            else
                return -1;
        }
    }

    public static void main(String[] args)
    {
        List<Person> people = new ArrayList<Person>();
        people.add( new Person("Homer", 38) );
        people.add( new Person("Marge", 35) );
        people.add( new Person("Bart", 15) );
        people.add( new Person("Lisa", 13) );

        // Sort by natural order

        Collections.sort(people);
        System.out.println("Sort by Natural order");
        System.out.println("\t" + people);

        // Sort by reverse natural order

        Collections.sort(people, Collections.reverseOrder());
        System.out.println("Sort by reverse natural order");
        System.out.println("\t" + people);

        //  Use a Comparator to sort by age

        Collections.sort(people, new Person.AgeComparator());
        System.out.println("Sort using Age Comparator");
        System.out.println("\t" + people);

        //  Use a Comparator to sort by descending age

        Collections.sort(people,
            Collections.reverseOrder(new Person.AgeComparator()));
        System.out.println("Sort using Reverse Age Comparator");
        System.out.println("\t" + people);
    }
}

这实际上对我有用,这也是一个非常简单的解决方案(只需一行)。
android开发人员

完美的例子!谢谢。
Michael Wildermuth 2013年

有没有办法使用这样的比较器对TreeSet中的字符串进行排序?同一件事,按年龄段的人。
Zeff520

我从来没有使用过TreeSet,但是API文档说-元素是按其自然顺序进行排序的,或者由在集合创建时提供的Comparator进行排序,具体取决于所使用的构造函数,因此我认为这是可能的。
camickr

17

我将为可以通过某种排序行为进行参数设置的人员类创建一个比较器。在这里,我可以设置排序顺序,但是可以对其进行修改以允许对其他人员属性进行排序。

public class PersonComparator implements Comparator<Person> {

  public enum SortOrder {ASCENDING, DESCENDING}

  private SortOrder sortOrder;

  public PersonComparator(SortOrder sortOrder) {
    this.sortOrder = sortOrder;
  }

  @Override
  public int compare(Person person1, Person person2) {
    Integer age1 = person1.getAge();
    Integer age2 = person2.getAge();
    int compare = Math.signum(age1.compareTo(age2));

    if (sortOrder == ASCENDING) {
      return compare;
    } else {
      return compare * (-1);
    }
  }
}

(希望它现在可以编译,我手边没有IDE或JDK,编码为“ blind”)

编辑

感谢Thomas,编辑了代码。我不会说Math.signum的用法很好,高效,有效,但我想提醒一下,compareTo方法可以返回任何整数,并且如果()乘以(-1)将失败。实现返回Integer.MIN_INTEGER ...并且我删除了setter,因为它便宜得足以在需要时构造一个新的PersonComparator。

但是我保留拳击内容,因为它表明我依赖现有的Comparable实现。可以做类似的事情,Comparable<Integer> age1 = new Integer(person1.getAge());但是看起来太丑陋了。这个想法是要展示一种模式,该模式可以轻松地适应其他“人”属性,例如姓名,生日和日期等。


6
曾几何时,有一种习惯是发表评论以帮助刚被投票否定的作者改善他的信息。
Andreas Dolk

我没有投票,但是compare * (-1)容易溢出。我在最初的帖子中犯了同样的错误。
Thomas Jung

并且SortOrder应该在构造函数中设置并且是最终的。我认为使用包装器是一种更好的方法:new Reverse(new PersonComparator())
Thomas Jung,

并且Integer age1 = ...;有拳击的开销。
Thomas Jung

是的,是的,是的,还有足够的改进空间。装箱是故意的,设置器允许使用比较器进行升序和降序-另一方面,您是对的,最好每次创建一个新的,然后再使用它。建造足够便宜。
Andreas Dolk,2009年

14
String[] s = {"a", "x", "y"};
Arrays.sort(s, new Comparator<String>() {

    @Override
    public int compare(String o1, String o2) {
        return o2.compareTo(o1);
    }
});
System.out.println(Arrays.toString(s));

-> [y, x, a]

现在,您必须为您的Person类实现Comparator。诸如(按升序排列):compare(Person a, Person b) = a.id < b.id ? -1 : (a.id == b.id) ? 0 : 1Integer.valueOf(a.id).compareTo(Integer.valueOf(b.id))

为了最大程度地减少混乱,您应该实现一个升序比较器,并使用包装器将其转换为降序比较器(像这样new ReverseComparator<Person>(new PersonComparator())


现在,这是一个令人困惑的示例,因为String实现了Comparable。-1没有最直接的东西。
博佐

1
反对-1 * x的最佳论据是-1 * Integer.MIN_VALUE == Integer.MIN_VALUE。这不是您想要的。我换了更容易的论点。
Thomas Jung

1
我想这是一个ReverseComparator,而不是Reserve ...
Adriaan Koster

好吧,那不是最好的说法。这对初学者来说只是令人困惑:)仍然如此,因为这将要求他知道什么是Comparable,并意识到他的Person并没有实现它。但是,然后-认为这是一件好事:)
Bozho

Integer.compare在其文档中提到了以下内容:The value returned is identical to what would be returned by: Integer.valueOf(x).compareTo(Integer.valueOf(y)),因此您可以Integer.compare改用。
按键

5

使用Google收藏集:

class Person {
 private int age;

 public static Function<Person, Integer> GET_AGE =
  new Function<Person, Integer> {
   public Integer apply(Person p) { return p.age; }
  };

}

public static void main(String[] args) {
 ArrayList<Person> people;
 // Populate the list...

 Collections.sort(people, Ordering.natural().onResultOf(Person.GET_AGE).reverse());
}

0
package com.test;

import java.util.Arrays;

public class Person implements Comparable {

private int age;

private Person(int age) {
    super();
    this.age = age;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

@Override
public int compareTo(Object o) {
    Person other = (Person)o;
    if (this == other)
        return 0;
    if (this.age < other.age) return 1;
    else if (this.age == other.age) return 0;
    else return -1;

}

public static void main(String[] args) {

    Person[] arr = new Person[4];
    arr[0] = new Person(50);
    arr[1] = new Person(20);
    arr[2] = new Person(10);
    arr[3] = new Person(90);

    Arrays.sort(arr);

    for (int i=0; i < arr.length; i++ ) {
        System.out.println(arr[i].age);
    }
}

}

这是一种方法。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.