2011-02-10 86 views
9

假设我有一组字符串,我希望按长度排序,但通过正常的String唯一性排序。我的意思是,我可以在Set中有多个相同长度的字符串,但它们应该按照长度排序。Scala SortedSet - 按一个排序排序并由其他内容唯一排序?

我想表达的是这样的顺序:

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) 

我只得到'bar'。这是因为Ordering代表总排序,因此当compare返回0时,元素被视为相同。

因此,我想我需要做一个链接的顺序和比较字符串,如果长度是相等的。要做到这一点我用这样的“皮条客我的图书馆” -pattern:

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] 

我认为它看起来真的很棒,但后来我意识到,我想要做的并不是通过字符串的自然顺序来排序,我只是想按大小排序,而不是按别的排序。这是否可能以更优雅的方式?

回答

18

我在这样的情况下,这样做是这样的:

val orderByLength = Ordering[(Int, String)].on[String](s => s.length -> s) 

换句话说,使用一个元组获得决胜。

在另一方面,我认为这是愚蠢的SortedSet根据自己排序考虑要素是相同的。我认为这已经在之前讨论过了,但我不会放弃搜索邮件列表存档和scala trac进行讨论/票据的可能性,也可能试图让SortedSet改变它的行为。

+4

一组只包含不同的对象。排序集合具有总排序。特别是,`S包含a`,`S包含b`意味着`a 2011-02-10 03:39:25