2011-02-10 33 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