升序和降序排列列表的规则是怎样的?

How is the rule for sorting a list in ascending order and descending order?

我一直在尝试了解使用 Comparable 进行排序的方式。我有 class Activity 实现 Comparable 接口。我试图了解 activity.finish-this.finish;按降序排序以及 this.finish-activity.finish 如何按升序排序。我很困惑升序和降序排序先用什么?

class Activity implements Comparable {
    int start;
    int finish;

    public Activity(int start, int finish) {
        this.start = start;
        this.finish = finish;
    }

    @Override
    public int compareTo(Object o) {
        Activity activity = (Activity) o;
        return  activity.finish-this.finish;
    }
}

public class ActivitySelectionProblem {
    public static void main(String[] args) {
        int start[]  =  {1, 3, 0, 5, 8, 5};
        int finish[] =  {2, 4, 10, 7, 9, 9};

        List<Activity> list = new ArrayList<>();
        for(int i = 0 ; i < start.length ; i++){
            list.add(new Activity(start[i], finish[i]));
        }

        Collections.sort(list);
    }
}

这很老套。 compareTo is that it returns less than 0 when the result of comparison is less, greater than 0 when greater and 0 when equal. It is not obvious what the code does. Instead, I would use Integer.compare(int, int) 的合同 - 类似于

@Override
public int compareTo(Object o) {
    return Integer.compare(this.finish, ((Activity) o).finish);
}

Answer by Elliott Frisch 是正确的。此外,请考虑根据您的情况使用 Comparator 而不是 Comparable

tl;博士

Collections.sort(                                       // Utility method for sorting a `List`. 
    activitiesAscending ,                               // A list copied from your original list of inputs.
    Comparator.comparingInt( Activity :: finish )       // A predefined implementation of `Comparator` interface, built for comparing `int` values.    
);                                                      // Results in the passed list being modified, being sorted according to the logic of the passed `Comparator`. 

Collections.sort( 
    activitiesDescending , 
    Collections.reverseOrder(                           // Reverses the sorting logic of the passed `Comparator` object.
        Comparator.comparingInt( Activity :: finish )   // Same `Comparator` as seen above.
    ) 
);

compareToequals

一致

另一个问题是,如果您阅读 Comparable 的 Java 文档,您会发现通常 compareTo 的逻辑最好与equals.

的逻辑

但是您希望只在 finish 成员字段上进行比较。所以你应该写你的equals(和hashCode)也只关注finish。但这意味着您在问题中看到的最后两个对象将被视为相等,因为它们都共享 9finish 值。我希望你不会认为这两个对象是相等的。

Comparator

在 class 之外定义 Comparator 可能比让 Activity class 实现 Comparable.我们将在本答案的其余部分中这样做。

使用 Java 16,我们可以将您的 Activity class 定义为 record。编译器隐式创建构造函数 getters、equals & hashCodetoString。使用 record 对这个答案并不重要,但可以使示例代码简短。

package work.basil.example;

public record Activity( int start , int finish )
{
}

Comparator.comparingInt

我们可以使用 predefined comparator for comparing int values.

而不是定义您自己的 Comparator 接口实现

我们使用 method reference 使用双冒号字符来命名应该用于从被比较对象中检索 int 的方法。该方法参考是 Activity :: finish。在记录中,默认的 getter 方法与 属性 名称相同,没有 JavaBeans 常见的 get 前缀。所以简单地 finish 作为方法名称,而不是 getFinish.

Comparator.comparingInt( Activity :: finish ) ) // Method reference from `Activity` being passed to `Comparator` built to compare `int` values.

让我们使用方便的 List.of 语法定义您的输入。

List < Activity > activities =
        List.of(
                new Activity( 1 , 2 ) ,
                new Activity( 3 , 4 ) ,
                new Activity( 0 , 10 ) ,
                new Activity( 5 , 7 ) ,
                new Activity( 8 , 9 ) ,
                new Activity( 5 , 9 )
        );

该代码生成的列表是 unmodifiable. We want to sort a list, so we need a modifiable list. Feed that unmodifiable list to the constructor of a modifiable implementation of List such as ArrayList

List < Activity > activitiesAscending = new ArrayList <>( activities );

请求实用程序方法 Collections.sort 对新列表进行排序。如前所述传递 Comparator

Collections.sort( activitiesAscending , Comparator.comparingInt( Activity :: finish ) );

相反,按照降序排列,您的 9 个完成对象在前,您的 2 个完成对象在最后,我们再次调用 Collections.sort。但是我们传递了一个不同的Comparator。我们将原始 comparingInt 比较器传递给实用方法 Collections.reverseOrder 以生成新的比较器。

List < Activity > activitiesDescending = new ArrayList <>( activities );
Collections.sort( activitiesDescending , Collections.reverseOrder( Comparator.comparingInt( Activity :: finish ) ) );

完整的代码示例。

List < Activity > activities =
        List.of(
                new Activity( 1 , 2 ) ,
                new Activity( 3 , 4 ) ,
                new Activity( 0 , 10 ) ,
                new Activity( 5 , 7 ) ,
                new Activity( 8 , 9 ) ,
                new Activity( 5 , 9 )
        );

List < Activity > activitiesAscending = new ArrayList <>( activities );
Collections.sort( activitiesAscending , Comparator.comparingInt( Activity :: finish ) );

List < Activity > activitiesDescending = new ArrayList <>( activities );
Collections.sort( activitiesDescending , Collections.reverseOrder( Comparator.comparingInt( Activity :: finish ) ) );

System.out.println( "activities = " + activities );
System.out.println( "activitiesAscending = " + activitiesAscending );
System.out.println( "activitiesDescending = " + activitiesDescending );

当运行.

activities = [Activity[start=1, finish=2], Activity[start=3, finish=4], Activity[start=0, finish=10], Activity[start=5, finish=7], Activity[start=8, finish=9], Activity[start=5, finish=9]]
activitiesAscending = [Activity[start=1, finish=2], Activity[start=3, finish=4], Activity[start=5, finish=7], Activity[start=8, finish=9], Activity[start=5, finish=9], Activity[start=0, finish=10]]
activitiesDescending = [Activity[start=0, finish=10], Activity[start=8, finish=9], Activity[start=5, finish=9], Activity[start=5, finish=7], Activity[start=3, finish=4], Activity[start=1, finish=2]]