Reputation: 847
I'm trying to sort an array of objects. When i try to use sortWith function to sort only one field in the object, it works perfectly fine. When multiple fields are sorted, then it messes up.
For eg.
scala> val res = branches.collect.toList
res: Array[(String, String, String)] = Array((109,A,Australia), (101,A,Australia), (102,A,Myanmar), (103,B,Australia), (104,A,Europe), (105,B,US), (106,B,Myanmar), (107,C,Australia), (108,A,Canada))
scala> val a = res.sortWith((x,y) => (x._2 < y._2 && x._1 > y._1))
Basically im trying to sort 2nd tuple and based on the result i'm sorting the first tuple. I get the following result, which is not sorted properly. I understand that the same can be achieved with sortBy function also. But i would like to understand how the sortWith works.
scala> val a = res.sortWith((x,y) => (x._2 < y._2 && x._1 > y._1))
a: Array[(String, String, String)] = Array((109,A,Australia), (107,C,Australia), (101,A,Australia), (102,A,Myanmar), (104,A,Europe), (108,A,Canada), (103,B,Australia), (105,B,US), (106,B,Myanmar))
Upvotes: 6
Views: 6986
Reputation: 20415
A simple approach with sortBy
,
res.sortBy(t => (t._2, -t._1))
which sorts first by the second item in the tuple in ascending order, and in case of equality, sorts by the first item, in descending order. Note we use of the negation (minus here) to revert the default ordering.
Upvotes: 11
Reputation: 546
Your problem is in your predicate. Consider the comparison of (101,A, Australia) with (102,A, Myanmar): Your sort function says the first tuple is smaller when both the second element is smaller and the first element is larger - i.e when A
Similarly, if you reverse the comaprison, is (102,A,Myanmar) < (101,A,Australia)? here you need A
So the sorting algorithm sees these that neither of elements is less than the other, so they are equal for sort purposes, and using a stable sort, leaves them in the original order. Try reversing those two elements in your inoput and see that they appear in the result in the order you put them in.
The sort predicate you need is: (x._2 < y._2 ||(x._2 == y._2 && x._1 > y.1))) - this will first compare the second element of the tuples, so (,A,) will always be less than (,B,_), however when the second elements are equal, it will then indicate less than for case where the first element is larger.
The key here is that you want to use the secondary comparison (x._1>y._1) only when the primary comparison (x._2 with y._2) is equal.
Upvotes: 10