Search code examples
javacode-reuse

How to write a function using natural order and comparators


I am new to Java, and I am trying to implement a sort algorithm which may use the natural order or a given comparator argument.

Say I have a comparable class C with some natural order compareTo, a Comparator subclass ByAltOrder, And I have a Comparator<C> method which returns a new 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) { ... }
    }
}

I want to write a function which may use the natural order or the alternative order. I know how to write a function that uses either the natural order or the alternative order, but I do not want to write the same code twice with minor differences. Is that possible?

Say I want to write a function returning maximum of a non-empty Array. With natural order it looks like this:

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

And with Comparator it looks like this and I can pass x.altOrder() as the second argument:

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

But how I do write a function that incorporates both?

Edit: I got that there is an Arrays.sort in Java, but implementing sort or max is just a toy example for my question about passing Comparators / code reuse / java practice. Perhaps I didn't make it clear about this.


Solution

  • Technically JB Nizet is right.
    This is enough :

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

    Now, concretely, writing these processings seem not relevant
    To find the max element (in terms of Comparable/Comparator) of an array, you could just use Arrays.stream().max :

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

    or

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

    By handling the null case if the array is empty (thanks dear Holger), your methods could be as simple as :

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