1

I have following classes-

public class Pair
{
    public double value;
    int id;

    Pair(){
        value=0;
        id=0;
    }
    Pair(double value, int id){
        this.value=value;
        this.id=id;
    }
}

PairComparator class to be used for implementing Comparator class

public class PairComparator implements Comparator<Pair>{
    @Override
    public int compare(Pair p1, Pair p2){
        return (int)(p2.value-p1.value);
    }
}

I'm trying to sort a Pair collection as follows-

List<Pair> list= new ArrayList<Pair>();
list.add(new Pair(5.2, 4));
list.add(new Pair(3.4, 5));
list.add(new Pair(10.3, 3));

Collections.sort(list, new PairComparator());

However I'm getting following error-

`Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:895)
at java.util.TimSort.mergeAt(TimSort.java:512)
at java.util.TimSort.mergeCollapse(TimSort.java:435)
at java.util.TimSort.sort(TimSort.java:241)
at java.util.Arrays.sort(Arrays.java:1512)
at java.util.ArrayList.sort(ArrayList.java:1454)
at java.util.Collections.sort(Collections.java:175)
at com.research.priyanshuid.recommendation_system.MatrixRecalculation.main(MatrixRecalculation.java:59)
Chris Martin
  • 30,334
  • 10
  • 78
  • 137
  • @MadushanPerera I don't exactly have the list items as inserted in the above code, do you think that the code might be producing error due to problem in the data? – Priyansu Singh Nov 23 '15 at 05:52
  • No if you did not provide the list items it should compile and run fine but without any out-put. – Madushan Perera Nov 23 '15 at 05:56
  • I mean I have data in the list but it is not inserted in the way as done in the above list, so is it possible that the comparator class gives this particular error because of the incompatibility of datatype? – Priyansu Singh Nov 23 '15 at 05:59
  • Incompatibility of datatype right away gives you a compile error since you cant pass String value as the first parameter of your `Pair` class constructor . – Madushan Perera Nov 23 '15 at 06:15
  • "is not inserted in the way as done in the above list" so which way you have inserted ??? – Madushan Perera Nov 23 '15 at 06:16
  • You better check documentation for further details.. http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html#compare%28T,%20T%29 – Madushan Perera Nov 23 '15 at 06:17
  • Possible duplicate of ["Comparison method violates its general contract!"](http://stackoverflow.com/questions/8327514/comparison-method-violates-its-general-contract) – Oleg Estekhin Nov 23 '15 at 06:29

3 Answers3

5

You usually get this error when the comparator violates the transitivity - check this answer.

When using double in a Comparator, you should avoid using the substraction logic. Since you're converting the result into an int, it would be rounded and thus would break transitivity while comparing values like 5.1, 5.2 etc. Check this answer for details.

You're better off using a comparator logic as so:

public int compare(Pair p1, Pair p2) {
   if (p1.value < p2.value) return -1;
   if (p1.value > p2.value) return 1;
   return 0;
}

As mentioned by sarilks - if you're expecting NaN values better use in-built compare function -

public int compare(Pair p1, Pair p2){
    return Double.compare(p1.value, p2.value);
}
Community
  • 1
  • 1
Vinay Rao
  • 1,284
  • 9
  • 13
4

Since you are comparing Double values , its safer to use Double.compare

 public int compare(Pair p1, Pair p2){
    return Double.compare(p1.value, p2.value);
}
Saril Sudhakaran
  • 1,109
  • 9
  • 17
4

In Java-8 you can do this safely and without additional PairComparator class:

Collections.sort(list, Comparator.comparingDouble(p -> p.value));
Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334