Question

Currently I am writing a compareTo method for quadratic functions in the form: ax^2 + bx + c.

a, b, c are integer coefficients that are passed to the class through the constructor.

In the compareTo method, I am supposed to first compare the a-coefficients between two functions, but if they are equal, I compare the b-coefficients. If the b's are equal, I compare the c's.

The method that I came up for this ended up being pretty ugly:

public int compareTo(QuadraticFunction other)
{
    if (a > other.a)
        return 1;
    else if (a < other.a)
        return -1;
    else if (b > other.b)
        return 1;
    else if (b < other.b)
        return -1;
    else if (c > other.c)
        return 1;
    else if (c < other.c)
        return -1;
    else
        return 0;
}

So I was wondering, if you have these "tiered" systems of comparisons (like compare a's before b's before c's), what's the best way to implement them? I can't imagine writing a method like mine if you have to go through 10+ variables.

Was it helpful?

Solution

For an arbitrary number of coefficients (all of the same type), you should store them in a List (or something similar), rather than individually-named member variables. That allows you to convert your example code into an iteration.

OTHER TIPS

The Guava Libraries provide an extremely nice tool to do this called ComparisonChain.

Your code would look something like this:

import com.google.common.base.ComparisonChain;
...
public int compareTo(QuadraticFunction other) {
  return ComparisonChain.start()
    .compare(a, other.a)
    .compare(b, other.b)
    .compare(c, other.c)
    .result();
}

For readability, and to use the built-in compare methods for a, b, c, I would refactor to this:

public int compareTo(QuadraticFunction other) {
    if (a.equals(other.a)) {
        if (b.equals(other.b))
            return c.compareTo(other.c);
        return b.comapreTo(other.b);
    }
    return a.compareTo(other.a);
}

This code assumes the fields are Number. If they are a primitive, either convert them to wrapped type or change a.equals(b) toa == band changea.compareTo(b)toa - b`.

Also note that when an if returns, there is never a need for an else - it's redundant, so remove it.

You can use an idiom like the below which breaks the comparison into clear sections by field, only requires one test per field, and uses the signum method to produce the return values.

Note, the subtraction below works for int, short, char, or byte fields. For long, float, and double fields you have to use separate checks for < and == to avoid overflow/underflow, and loss of precision due to rounding. Be careful of NaN too when comparing floating point values. For Comparable fields, you can just set delta to the result of compareTo after using separate conditions to handle null.

long delta = ((long) a.field1) - b.field1;
if (delta != 0) { return Long.signum(delta); }

delta = ((long) a.field2) - b.field2;
if (delta != 0) { return Long.signum(delta); }

...

return 0;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top