假设我有一组字符串,我希望按长度排序,但按正常String
唯一性排序。我的意思是我可以在Set
中拥有多个相同长度的字符串,但是它们应该按长度排序。
我想表达这样的顺序:
val orderByLength = Ordering[Int].on[String](_ length)
我认为看起来非常好。但是如果我把它扔进SortedSet,就像这样说:
scala> val s = SortedSet("foo", "bar")(orderByLength)
s: scala.collection.immutable.SortedSet[java.lang.String] = TreeSet(bar)
我只得到'酒吧'。这是因为Ordering
表示总排序,因此当compare
返回0时,元素被认为是相同的。
因此,我认为如果长度相等,我需要进行链式排序并比较字符串。要做到这一点,我使用了“pimp my library” - 像这样的模式:
trait ChainableOrderings {
class ChainableOrdering[T](val outer: Ordering[T]) {
def ifEqual(next: Ordering[T]): Ordering[T] = new Ordering[T] {
def compare(t1: T, t2: T) = {
val first = outer.compare(t1, t2)
if (first != 0) first else next.compare(t1, t2)
}
}
}
implicit def chainOrdering[T](o: Ordering[T]) = new ChainableOrdering[T](o)
}
我可以使用:
val ordering = Ordering[Int].on[String](_ length) ifEqual Ordering[String]
我觉得它看起来真的很棒,但后来我意识到我想要做的并不是按照字符串的自然顺序排序,我只是想按尺寸排序,而是通过别的东西来排序。这有可能以更优雅的方式实现吗?
答案 0 :(得分:18)
在这种情况下我做的是:
val orderByLength = Ordering[(Int, String)].on[String](s => s.length -> s)
换句话说,使用元组来获得决胜局。
另一方面,我认为SortedSet
基于他们的排序来考虑元素是愚蠢的。我认为之前已经讨论过这个问题,但是我不会放弃搜索邮件列表档案和scala trac讨论/票证的可能性,也许会尝试让SortedSet
改变其行为。