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.
Use the
Orderingtypeclass:This adds another parameter list to
fwith an implicitOrderingparameter. The method signature is actually translated to this behind the scene:The
evidenceparameter is then picked up bysortByand used for comparing elements.EDIT:
Note that you cannot use
Orderedin the same way asOrdering. TheOrderedtrait is meant to be mixed in with the very object type that will be sorted (like in Java). In other words,Awould have to extendOrdered[A]and then you would write it asA <: Ordered[A].However, this inheritance approach with
Orderedis less powerful than the typeclass approach withOrdering, because it is less flexible. If somebody else definedAand didn’t decide to make it extendOrdered[A], then you wouldn’t be able to use it withsortBy(at least not without creating a wrapper class). On the other hand, you can always declare a new implicitOrdering[A]in scope without changing whatAinherits, and implement thisOrderingin any way you like. This allows you both to define how the objects of typeAare ordered when the implementer ofAhas forgotten to do so, and to redefine how they are ordered when you want a non-default ordering.