2

I'm currently having some trouble understanding how the compareTo method works for the Comparable class, and how to override it. I have array of pairs, each of which hold 2 double values, that I'm trying to sort. This is what I tried:

static class Pair implements Comparable<Pair>
{
    double x;
    double y;
    Pair(double x, double y)
    {
        this.x = x;
        this.y = y;
    }
    public double compareTo(Pair other)
    {
        return y - other.y;
    }
}

However, it doesn't compile and instead gives me this error:

Main.java:5: error: Pair is not abstract and does not override abstract method compareTo(Pair) in Comparable
    static class Pair implements Comparable<Pair>
           ^
Main.java:14: error: compareTo(Pair) in Pair cannot implement compareTo(T) in Comparable
        public double compareTo(Pair other)
                      ^
  return type double is not compatible with int
  where T is a type-variable:
    T extends Object declared in interface Comparable
2 errors

It worked when it was with integers, but not with doubles, why is that? And how could I make it work with doubles? Thanks.

  • 5
    [`compareTo` returns an `int`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Comparable.html#compareTo(T)), not a double. It's spelled out in the error as well. – Federico klez Culloca Jan 20 '21 at 20:29
  • Don't you need to specify the generic parameters to `Pair`? – Ruan Mendes Jan 20 '21 at 20:30
  • How can I modify to make it work with doubles? – Sankeeth Ganeswaran Jan 20 '21 at 20:32
  • @JuanMendes The class `Pair` as given does not have any generic type parameters; and if it had, `double` would not be a valid type to use with them, because it is a primitive type. – khelwood Jan 20 '21 at 20:35
  • @khelwood I must be thinking of a (different Pair)[https://docs.oracle.com/javase/9/docs/api/javafx/util/Pair.html]? And i thought they would get auto boxed :p – Ruan Mendes Jan 21 '21 at 19:10

4 Answers4

5

This can be generalised to below implementation to work with any Pair that whose T,V implements Comparable interface. It is generally pointless to compare objects of classes that are not comparable (In a perfect world!).

public class GenComparableStackOverflow {
  public static void main(String[] args){
    Pair<Double,Double> pair1 = new Pair<>(2.0,2.0);
    Pair<Double,Double> pair2 = new Pair<>(4.0,1.0);
    Stream.of(pair1,pair2).sorted().forEach(System.out::println); //Uses compareTo
  }

}

class Pair<T extends Comparable<T>,V extends Comparable<V>> implements Comparable<Pair<T,V>> {
  T x;
  V y;

  Pair(T x, V y) {
    this.x = x;
    this.y = y;
  }

  @Override
  public String toString() {
    return "Pair{" +
        "x=" + x +
        ", y=" + y +
        '}';
  }

  @Override
  public int compareTo(Pair<T, V> o) {
    return this.y.compareTo(o.y);
  }
}

This is better than your custom implementation because the classes that are Comparable will already be having a compareTo() method overridden. For your case, this will be using Double.compareTo() without even your knowledge :)

Mohamed Anees A
  • 4,119
  • 1
  • 22
  • 35
3

compareTo has to return an int. You can use Double.compare.

public int compareTo(Pair other) {
    return Double.compare(y, other.y);
}
Martin Väth
  • 226
  • 1
  • 2
  • 3
2

For example:

   static class Pair implements Comparable<Pair> {

        double x;
        double y;

        Pair(double x, double y) {
            this.x = x;
            this.y = y;
        }

        public int compareTo(Pair other) {
            if (y > other.y) {
                return 1;
            } else if(y<other.y)  {
                return -1;
            } else {
                return 0;
            }
        }
    }

or (better variant):

    static class Pair implements Comparable<Pair> {

        double x;
        double y;

        Pair(double x, double y) {
            this.x = x;
            this.y = y;
        }

        public int compareTo(Pair other) {
            return Double.compare(this.y, other.y);
        }
    }
yuri777
  • 377
  • 3
  • 7
  • 4
    A compareTo method that can never return zero is wrong. Just use [Double.compare](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Double.html#compare(double,double)) instead of doing it yourself. – VGR Jan 20 '21 at 21:04
  • I just showed the example. Of course logic of comparing can be more difficult and include field **x** too. – yuri777 Jan 20 '21 at 21:18
  • 2
    People are likely to copy code directly from an accepted answer. If your code isn’t completely correct, either edit your answer and say so, or fix it so it is correct. – VGR Jan 20 '21 at 21:34
  • I added `return 0` for equal field **y**. – yuri777 Jan 20 '21 at 21:37
  • 4
    A good reason to use `Double.compare` is that it handles edge cases (specifically `NaN`). Your code would say that 10 and NaN are "equal". – Andy Turner Jan 20 '21 at 21:41
  • I agree. I added new variant. – yuri777 Jan 20 '21 at 21:51
  • Oops...deleted it... :) @AndyTurner – Mohamed Anees A Jan 21 '21 at 13:57
1

If you want a general-purpose Pair class, see the correct Answer by Mohamed Anees A.

If you want to go with your idea of a Pair class specifically for double primitive type, then consider the following code.

record feature

For brevity and simplicity, I use the new record feature in Java 16.

As a record, the constructor, getters, toString, and equals/hashCode are provided implicitly by the compiler.

Double.compare

For the comparison work, we simply delegate to the static Double.compare method that compares two double primitives. This technique was seen in the second variant of the Answer by yuri777.

Here is the complete Pair class.

record Pair(double x , double y) implements Comparable < Pair >
{
    @Override
    public int compareTo ( Pair o )
    {
        return Double.compare( this.y , o.y );
    }
}

Here is a complete example app to demonstrate.

package work.basil.example;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class App2
{
    public static void main ( String[] args )
    {
        App2 app = new App2();
        app.demo();
    }

    private void demo ( )
    {
        List < Pair > pairs = new ArrayList <>( 3 );
        pairs.add( new Pair( 2.1D , 3.1D ) );
        pairs.add( new Pair( 4D , 3D ) );
        pairs.add( new Pair( 1.1D , 1.1D ) );
        System.out.println( "pairs = " + pairs );

        Collections.sort( pairs );
        System.out.println( "pairs = " + pairs );
    }

    record Pair(double x , double y) implements Comparable < Pair >
    {
        @Override
        public int compareTo ( Pair o )
        {
            return Double.compare( this.y , o.y );
        }
    }
}

When run:

pairs = [Pair[x=2.1, y=3.1], Pair[x=4.0, y=3.0], Pair[x=1.1, y=1.1]]
pairs = [Pair[x=1.1, y=1.1], Pair[x=4.0, y=3.0], Pair[x=2.1, y=3.1]]
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154