views:

223

answers:

2

Hi everyone,

I just want to use Collections.sort or Arrays.sort to sort a list of points (class Point) by x first and then by y.

I have a class Ponto that implements Comparable like this:

public int compareTo(Ponto obj) {
        Ponto tmp = obj;
        if (this.x < tmp.x) {
            return -1;
        } else if (this.x > tmp.x) {
            return 1;
        }
        return 0;
    }

but now I want to sort by y too after x.

How can I do that by modifying the above code? Or is that a better and "clean" way to do this? I also use to pass this code to C++, in which I've created a structure called Point with a equivalent comparable method.

+6  A: 

Replace return 0 by the same comparison algo on this.y and obj.y.

By the way, reassigning to tmp is unnecessary here. The optimized picture can look like:

public int compareTo(Ponto other) {
    if (this.x == other.x) {
        return (this.y < other.y) ? -1 : ((this.y == other.y) ? 0 : 1);
    } else {
        return (this.x < other.x) ? -1 : 1;
    }
}
BalusC
Of course, you shouldn't use this subtraction technique unless you can guarantee that it will not overflow (see http://stackoverflow.com/questions/2728793/java-integer-what-is-faster-comparison-or-subtraction/)
polygenelubricants
@poly: Very true, bit silly of me, updated answer.
BalusC
+1  A: 

BalusC provides the correct answer: basically you give priority to x over y. Here's a variant written using nested ternary operators that makes the priority clear.

public int compareTo(Ponto other) {
    return
      (this.x < other.x) ? -1 :
      (this.x > other.x) ? +1 :
      (this.y < other.y) ? -1 :
      (this.y > other.y) ? +1 :
      0;
}

Another way to do this, if you don't want to write a custom Comparator<T> for every priority scheme, is to do multiple sort using a stable algorithm.

If you want to order by x (primary), and then y (secondary), then:

  • Sort on y first (!!!)
  • Then sort on x using a stable sort

This is asymptotically still O(N log N) but of course you're doing multiple phases. It's convenient when you have many sorting criterias. Rather than writing the complex code, just do the multiple phase (and only optimize if/when proven necessary).

So if you have sorting keys k1, k2, k3, ..., kM, in that order of priority, you do:

  • Sort on kM
  • Stable sort on kM-1
  • ...
  • Stable sort on k1
  • DONE!

Note that Collections.sort is stable.

This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.

polygenelubricants
This one is indeed better readable :)
BalusC
@BalusC: only if you're comfortable with nested ternary. I've been screamed at for using it before.
polygenelubricants
You get used to it after years. It's like delicious liquor for the old as compared to tasteless beer for the young.
BalusC
And what if I use Ponto[] list and then sort it with Arrays.sort(list), is it as stable as Collections.sort?This is for a contest, but fortunatelly I know that my list will have no more than 50 elements.
neverMind
@newba: you should learn how to read the documentation; that way you can answer these kinds of questions on your own quickly: http://java.sun.com/javase/6/docs/api/java/util/Arrays.html#sort%28java.lang.Object[]%29 "This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort."
polygenelubricants