I have tuples of the form (Boolean, Int, String)
.
I want to define Ordering which sorts the tuples in the following order:
Boolean - reverse order
Int - reverse order
String - regular order
Example:
For the tuples: Array((false, 8, "zz"), (false,3, "bb"), (true, 5, "cc"),(false, 3,"dd"))
.
The ordering should be:
(true, 5, "cc")
(false, 8,"zz")
(false, 3, "bb")
(false, 3, "dd")
I couldn't find a way to define some of the ordering reverse and some regular.
The straight forward solution in this specific case is to use sortBy
on the tuples, modified on the fly to "invert" the first and second elements so that in the end the ordering is reversed:
val a = Array((false, 8, "zz"), (false,3, "bb"), (true, 5, "cc"),(false, 3,"dd"))
a.sortBy{ case (x,y,z) => (!x, -y, z) }
For cases when you cannot easily "invert" a value (say that this is a reference object and you've got an opaque ordering on them), you can instead use
sorted
and explicitly pass an ordering that is constructed to invert the order on the first and second elements (you can use Ordering.reverse
to reverse an ordering):
val myOrdering: Ordering[(Boolean, Int, String)] = Ordering.Tuple3(Ordering.Boolean.reverse, Ordering.Int.reverse, Ordering.String)
a.sorted(myOrdering)
You could do something like this.
case class myTuple(t: (Boolean, Int, String)) extends Ordered[myTuple] {
def compare(that: myTuple):Int = {
val (x,y,z) =t
val (x1,y1,z1) = that.t
if (x.compare(x1) != 0) x.compare(x1)
else {
if (y.compare(y1) != 0) if (y.compare(y1) == 1) 0 else 1
else z.compareTo(z1)
}
}
}
val myList = Array((false, 8, "zz"), (false,3, "bb"), (true, 5, "cc"),(false, 3,"dd"))
implicit def tupleToBeordered(t: (Boolean, Int, String)) = new myTuple(t._1,t._2,t._3)
myList.sorted