Как переопределить метод compareTo для удвоения?

В настоящее время у меня возникают проблемы с пониманием того, как работает метод compareTo для класса Comparable и как его переопределить. У меня есть массив пар, каждая из которых содержит 2 двойных значения, которые я пытаюсь отсортировать. Вот что я пробовал:

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

Однако он не компилируется и вместо этого выдает эту ошибку:

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

Это работало, когда это было с целыми числами, но не с двойными, почему это? И как я могу заставить его работать с двойниками? Спасибо.


person Sankeeth Ganeswaran    schedule 20.01.2021    source источник
comment
compareTo возвращает int, а не двойной. В ошибке тоже написано.   -  person Federico klez Culloca    schedule 20.01.2021
comment
Вам не нужно указывать общие параметры для Pair<double,double>?   -  person Juan Mendes    schedule 20.01.2021
comment
Как я могу изменить, чтобы он работал с двойными?   -  person Sankeeth Ganeswaran    schedule 20.01.2021
comment
@JuanMendes Класс Pair в том виде, в каком он указан, не имеет параметров универсального типа; и если бы это было так, double не был бы допустимым типом для их использования, потому что это примитивный тип.   -  person khelwood    schedule 20.01.2021
comment
@khelwood Я, должно быть, думаю о (другой паре)[docs.oracle.com/javase/9/docs/api/javafx/util/Pair.html]? И я думал, что они будут автоматически упакованы :p   -  person Juan Mendes    schedule 21.01.2021


Ответы (4)


Например:

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

или (лучший вариант):

    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);
        }
    }
person yuri777    schedule 20.01.2021
comment
Метод compareTo, который никогда не может вернуть ноль, неверен. Просто используйте Double.compare вместо того, чтобы делать это самостоятельно. - person VGR; 21.01.2021
comment
Я просто показал пример. Конечно, логика сравнения может быть более сложной и включать также поле x. - person yuri777; 21.01.2021
comment
Люди, скорее всего, скопируют код непосредственно из принятого ответа. Если ваш код не совсем правильный, либо отредактируйте свой ответ и скажите об этом, либо исправьте его, чтобы он был правильным. - person VGR; 21.01.2021
comment
Я добавил return 0 для равного поля y. - person yuri777; 21.01.2021
comment
Хорошей причиной для использования Double.compare является то, что он обрабатывает крайние случаи (в частности, NaN). В вашем коде будет сказано, что 10 и NaN равны. - person Andy Turner; 21.01.2021
comment
Я согласен. Я добавил новый вариант. - person yuri777; 21.01.2021
comment
Упс... удалил... :) @AndyTurner - person Mohamed Anees A; 21.01.2021

Это может быть обобщено для реализации ниже для работы с любой парой, чьи T, V реализуют интерфейс Comparable. Вообще бессмысленно сравнивать объекты несопоставимых классов (В идеальном мире!).

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

Это лучше, чем ваша собственная реализация, потому что классы, которые являются Comparable, уже будут иметь переопределенный метод compareTo(). В вашем случае это будет использовать Double.compareTo() даже без вашего ведома :)

person Mohamed Anees A    schedule 20.01.2021

compareTo должен возвращать целое число. Вы можете использовать Double.compare.

public int compareTo(Pair other) {
    return Double.compare(y, other.y);
}
person Martin Väth    schedule 20.01.2021
comment
Это правильно, но было бы лучше, если бы в нем было больше деталей. - person VGR; 21.01.2021
comment
Ты прав; У меня было мало времени. Наконец, я добавил хотя бы фрагмент кода, чтобы было понятно, что я имел в виду. - person Martin Väth; 24.01.2021

Если вам нужен класс Pair общего назначения, см. правильный Ответ от Mohamed Anees A.

Если вы хотите реализовать свою идею класса Pair специально для примитивного типа double, рассмотрите следующий код.

record функция

Для краткости и простоты я использую новую функцию record в Java 16.

В качестве record конструктор, геттеры, toString и equals/hashCode неявно предоставляются компилятором.

Double.compare

Для сравнения мы просто делегируем статическому Double.compare, который сравнивает два примитива double. Этот метод был замечен во втором варианте ответа от yuri777.

Вот полный класс Pair.

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

Вот полный пример приложения для демонстрации.

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

При запуске:

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]]
person Basil Bourque    schedule 20.01.2021