I want to sort an array
of 2 dimensional arrays in Java according to some rules, let's say the distance from the origin. I saw several ways of doing it using Arrays.sort()
:
1) Arrays.sort(points, Comparator.comparing(p -> p[0]*p[0] + p[1]*p[1]));
2) Arrays.sort(points, (p1, p2) -> p1[0]*p1[0] + p1[1]*p1[1] - p2[0]*p2[0] - p2[1]*p2[1]);
3) Defining the class
:
class Point implements Comparable<Point>{
// class variables, constructor
public int compareTo(Point p) {
return (x*x + y*y).compareTo(p.x*p.x + p.y*p.y);
}
}
An array pts
of type Points
is then created and Arrays.sort(pts)
is used. My question is regarding 1) and 2): I see the difference between the but I do not understand when to use one and when to use the other and what exactly Comparator.comparing()
is doing. Why is the first solution carrying the information just with one point while the second need two points?
Comparator.comparing
is implemented as follows:
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
i.e. it uses the Function
you pass to it in order to transform each of the compared elements into a Comparable
, and then uses the Comparable
's compareTo
method.
When you are passing the function p -> p[0]*p[0] + p[1]*p[1]
, you are converting each point to its sum of squares. Then, when the Comparator
needs to compare two points, it compares the sum of squares of the two points, which is almost equivalent to computing the difference of the sums of squares of the two points (it's not exactly equivalent, since comparing two numbers by computing their difference can produce wrong output in case of numeric overflow).
That's exactly what your second Comparator
- (p1, p2) -> p1[0]*p1[0] + p1[1]*p1[1] - p2[0]*p2[0] - p2[1]*p2[1]
- does,
since p1[0]*p1[0] + p1[1]*p1[1] - p2[0]*p2[0] - p2[1]*p2[1] ==
(p1[0]*p1[0] + p1[1]*p1[1]) - (p2[0]*p2[0] + p2[1]*p2[1])
.
Using Comparator.comparing()
is safer, since it compares the sums of squares of the two points without computing their difference. It uses Double
's compareTo()
instead (assuming the coordinates of your points are Double
or double
).
In other words, the first alternative uses a Function
that needs just one point since this function tells Comprator.comparing
how to transform each of the 2 points.
On the other hand, the second alternative accepts 2 points (which are the required arguments of the Comparator.compare()
method) and determines the relative order of these 2 points.