grautur
grautur

Reputation: 30485

How to convert Map[A, B] into a key-value string sorted by String?

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

Answers (1)

axel22
axel22

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

Related Questions