Reputation: 30485
Suppose I have a Map:
val m = Map("foo" -> 10, "bar" -> 5)
I want to convert this into a String in the following format (keys and values are separated by ":", different elements are separated by ","):
"bar:5,foo:10"
Note that the keys are now ordered.
How do I write a function to perform this conversion generically? I tried
def f[A, B](m: Map[A, B]): String = {
m.toList.sortBy(_._1).map { x => x._1 + ":" + x._2 }.mkString(",")
}
But this doesn't work, because somehow I need to specify that A
is orderable. I'm not sure how to do this -- I tried adding an implicit Orderer
parameter to my function, but it didn't work.
Upvotes: 4
Views: 1371
Reputation: 32335
Use the Ordering
typeclass:
def f[A: Ordering, B](m: Map[A, B]): String = {
m.toList.sortBy(_._1).map { x => x._1 + ":" + x._2 }.mkString(",")
}
This adds another parameter list to f
with an implicit Ordering
parameter. The method signature is actually translated to this behind the scene:
def f[A, B](m: Map[A, B])(implicit evidence: Ordering[A]): String
The evidence
parameter is then picked up by sortBy
and used for comparing elements.
EDIT:
Note that you cannot use Ordered
in the same way as Ordering
. The Ordered
trait is meant to be mixed in with the very object type that will be sorted (like in Java). In other words, A
would have to extend Ordered[A]
and then you would write it as A <: Ordered[A]
.
However, this inheritance approach with Ordered
is less powerful than the typeclass approach with Ordering
, because it is less flexible. If somebody else defined A
and didn't decide to make it extend Ordered[A]
, then you wouldn't be able to use it with sortBy
(at least not without creating a wrapper class). On the other hand, you can always declare a new implicit Ordering[A]
in scope without changing what A
inherits, and implement this Ordering
in any way you like. This allows you both to define how the objects of type A
are ordered when the implementer of A
has forgotten to do so, and to redefine how they are ordered when you want a non-default ordering.
Upvotes: 8