我已经看到了这个问题How to sort a list in Scala by two fields?
这类似但不重复。
我可以使用前一个问题的答案轻松地对List[DataPoint]
进行排序:
case class DataPoint(keys: List[String], value: Double)
listOfDataPoints.sortBy(point => (point.keys(0), point.keys(1)))
但我不知道keys
中的项目数。我所知道的是,给定列表中的每个DataPoint
都具有相同数量的键,因此绝不会对List("a")
和List("a", "b")
进行排序。
那么如何用未知数量的键对列表进行排序呢?
答案 0 :(得分:3)
你想做的是
datapoints.sortby(_.keys)
这显然不起作用。当我们看一下sortby的签名时,很明显为什么它不起作用:
sortBy[B](f: (A) ⇒ B)(implicit ord: math.Ordering[B]): List[A]
您的B
是List[String]
,而您没有Ordering[List[String]]
的实例。那么我们该怎么办?我们提供一个!
我们需要做的是实施方法
def compare(x: T, y: T): Int
我们想比较以下内容:
我们的T在这里是字符串,但我们对T的所有需求都是可比较的,所以我们可以更一般。
def listOrdering[T](implicit ord: Ordering[T]): Ordering[List[T]] = new Ordering[List[T]] {
def compare(x: List[T], y: List[T]): Int = {
(x, y) match {
case (Nil, Nil) => 0 //both empty => equal
case (Nil, _) => -1 //one of the two empty => empty is the smallest
case (_, Nil) => 1 //one of the two empty => empty is the smallest
case (xhead :: xtail, yhead :: ytail) => {
val headdiff = ord.compare(xhead, yhead)
if (headdiff == 0) compare(xtail, ytail) //recursively compare the tails if equivalent
else (headdiff ) //otherwise, the difference in the heads
}
}
}
}
现在我们可以明确地为sortby方法提供排序:
datapoints.sortby(_.keys)(listOrdering)
或以隐含范围提供它们
[1]:你表示这种情况从未发生过,所以任何选择都足够好
答案 1 :(得分:1)
您可以定义自己的Ordering[List[String]]
。例如,您可以定义:
class ListOrdering[A](implicit aOrd: math.Ordering[A]) extends Ordering[List[A]] {
def compare(a1: List[A], a2: List[A]) = (a1, a2) match {
case (Nil, _) => if (a2.isEmpty) 0 else -1
case (_, Nil) => 1
case (h1 :: t1, h2 :: t2) => if (aOrd.compare(h1, h2) == 0) compare(t1, t2) else aOrd.compare(h1, h2)
}
}
然后在范围内的某处提供以下内容:
implicit val listOrd = new ListOrdering[String]
你可以写:
dps.sortBy(_.keys)
它应该有用。
请注意,我对ListOrdering
的定义被推广为可用于范围内具有隐式A
的任何类型Ordering[A]
,并且可以处理可变长度的列表(即使你这么说在您的情况下,您的密钥列表总是相同的长度。)