如何使用自然顺序和比较器编写函数

How to write a function using natural order and comparators

我是 Java 的新手,我正在尝试实现一种可以使用自然顺序或给定比较器参数的排序算法。

假设我有一个可比较的 class C 具有一些自然顺序 compareTo,一个比较子 class ByAltOrder,我有一个 Comparator<C> 方法其中 returns 一个新的 ByAltOrder.

public class C implements Comparable<C> {
        ...                                     //fields and constructor
    public int compareTo(C that) { ... }        //natural order
    public Comparator<C> altOrder() {           //some alternative order
        return new ByAltOrder();
    }
    public class ByAltOrder implements Comparator<C>{
        public int compare(C x, C y) { ... }
    }
}

我想写一个可以使用自然顺序或替代顺序的函数。我知道如何编写一个使用 自然顺序或替代顺序的函数,但我不想两次编写相同的代码,但差别很小。这可能吗?

假设我想编写一个返回非空数组最大值的函数。按照自然顺序,它看起来像这样:

public C max(C[] xs){
    res = xs[0];
    for (i = 1; i < xs.length; i++) {
        if (xs[i].compareTo(res) > 0) {
            res = points[i];
        }
    }
    return res;
}

对于比较器,它看起来像这样,我可以将 x.altOrder() 作为第二个参数传递:

public C max(C[] xs, Comparator c){
    res = xs[0];
    for (i = 1; i < xs.length; i++) {
        if (c.compare(xs[i], res) > 0) {
            res = points[i];
        }
    }
    return res;
}

但是我如何编写一个包含两者的函数?

编辑:我知道 Java 中有一个 Arrays.sort,但是实现 sort 或 max 只是我关于传递比较器/代码重用/java 的问题的玩具示例实践。可能是我没说清楚

从技术上讲,JB Nizet 是正确的。
这就够了:

public C max(C[] xs){
    return max(xs, Comparator.naturalOrder());
}

public C max(C[] xs, Comparator<? super C> c){
    C res = xs[0];
    for (int i = 1; i < xs.length; i++) {
        if (c.compare(xs[i], res) > 0) {
            res = points[i];
        }
    }
    return res;
}

现在,具体来说,编写这些处理似乎无关紧要
要查找数组的最大元素(根据 Comparable/Comparator),您可以只使用 Arrays.stream().max :

C max = Arrays.stream(xs).max(c); 

C max =  Arrays.stream(xs).max(new ByAltOrder());

如果数组为空(感谢亲爱的 Holger),通过处理 null 情况,您的方法可以像这样简单:

public C findMax(C[] xs){
   return findMax(xs, Comparator.naturalOrder());
}

public C findMax(C[] xs, Comparator<? super C> c){
    return Arrays.stream(xs).max(c).orElse(null);
}

你可以这样做:

public <C extends Comparable<? super C>> C max(C[] xs){
    return max(xs, Comparator.naturalOrder());
}

public <C> C max(C[] xs, Comparator<C> c){
    C res = xs[0];
    for (C x: xs) {
        if (c.compare(x, res) > 0) {
            res = x;
        }
    }
    return res;
}

如果您真的想避免代码重复,则根本不应该执行该操作。

Comparator<C> altOrder = …;
C[] array = …;
C naturalMax = Collections.max(Arrays.asList(array));// natural order
C altMax     = Collections.max(Arrays.asList(array), altOrder); // alternative order

请注意,Arrays.asList 不会复制,而只会包装数组,因此没有性能考虑阻止使用这些方法。

顺便说一下,ByAltOrderaltOrder() 应该都是 static,因为它们不依赖于 C.[=19= 的特定实例]

如果您想将这些方法作为练习来实现,其他答案已经指向它,请使用委托和 Comparator.naturalOrder()

如果您没有使用 Java 8 或更新版本,则此内置比较器不可用,但您可以使用 Collections.reverseOrder(Collections.reverseOrder()) 解决它以获得具有相同行为的比较器,但是,当然,您应该在迁移到 Java 8 或更新版本后立即将其替换为 Comparator.naturalOrder()