假设我有一张地图:
val m = Map("foo" -> 10, "bar" -> 5)
我想将其转换为以下格式的字符串(键和值用“:”分隔,不同的元素用“,”分隔):
"bar:5,foo:10"
请注意,现在已订购钥匙。
如何编写一个函数来执行此转换?我试过了
def f[A, B](m: Map[A, B]): String = {
m.toList.sortBy(_._1).map { x => x._1 + ":" + x._2 }.mkString(",")
}
但是这不起作用,因为我需要指定A
是可订购的。我不知道该怎么做 - 我尝试在我的函数中添加一个隐式Orderer
参数,但它不起作用。
答案 0 :(得分:8)
使用Ordering
类型类:
def f[A: Ordering, B](m: Map[A, B]): String = {
m.toList.sortBy(_._1).map { x => x._1 + ":" + x._2 }.mkString(",")
}
这会向f
添加另一个带有隐式Ordering
参数的参数列表。方法签名实际上是在场景后面翻译的:
def f[A, B](m: Map[A, B])(implicit evidence: Ordering[A]): String
然后由evidence
选取sortBy
参数并用于比较元素。
编辑:
请注意,您不能以与Ordered
相同的方式使用Ordering
。 Ordered
特征旨在与将要排序的对象类型(如Java中)混合在一起。换句话说,A
必须扩展Ordered[A]
,然后您将其编写为A <: Ordered[A]
。
但是,使用Ordered
的这种继承方法不如使用Ordering
的类型类方法强大,因为它不太灵活。如果其他人定义A
并且没有决定使其扩展Ordered[A]
,那么您将无法将其与sortBy
一起使用(至少在没有创建包装类的情况下) 。另一方面,您始终可以在范围内声明新的隐式Ordering[A]
,而无需更改A
继承的内容,并以您喜欢的任何方式实现此Ordering
。这允许您在A
的实现者忘记这样做时定义A
类型的对象的排序方式,并在需要非默认排序时重新定义它们的排序方式。 / p>