2011-02-10 10 views
9

Powiedz, że mam zestaw Ciągów, które chcę uporządkować według długości, ale niepowtarzalne przez zwykłą niepowtarzalność String. Mam na myśli to, że mogę mieć więcej niż jeden ciąg o tej samej długości w Set, ale powinny być posortowane według długości.Scala SortedSet - posortowane według Zamawiającego i niepowtarzalne według czegoś innego?

Chcę wyrazić kolejność takiego:

val orderByLength = Ordering[Int].on[String](_ length) 

który myślę wygląda naprawdę ładnie. Ale jeśli miałbym rzucić to w SortedSet, powiedzieć tak:

scala> val s = SortedSet("foo", "bar")(orderByLength) 
s: scala.collection.immutable.SortedSet[java.lang.String] = TreeSet(bar) 

mam tylko „bar”. Dzieje się tak, ponieważ Ordering reprezentuje całkowitą kolejność, a gdy compare zwraca 0, elementy są uważane za identyczne.

Dlatego myślę, że muszę wykonać przykuty porządek i porównać ciągi, jeśli długości są równe. Aby to zrobić, użyłem „pimp my biblioteki” -pattern takiego:

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) 
} 

że można używać jak:

val ordering = Ordering[Int].on[String](_ length) ifEqual Ordering[String] 

myślałem, że wyglądała naprawdę świetnie, ale potem zdałem sobie sprawę, że to, co ja Chciałem zrobić, żeby nie było porządkiem według naturalnego uporządkowania Strings, chciałem tylko zamówić według wielkości, ale wyjątkowość przez coś innego. Czy jest to możliwe w bardziej elegancki sposób?

Odpowiedz

18

Co zrobić w takich sytuacjach to:

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

Innymi słowy, należy użyć krotki dostać tie-breaker.

Z drugiej strony, myślę, że to głupie, aby SortedSet rozważyć elementy takie same w oparciu o ich zamawiania. Myślę, że było to już wcześniej dyskutowane, ale nie odrzucałbym możliwości przeszukiwania archiwów list mailingowych i scala trac pod dyskusje/bilety na ten temat, i być może próbując uzyskać SortedSet zmienić jego zachowanie.

+4

Zestaw zawiera tylko różne obiekty. Sortowany zestaw ma całkowitą kolejność. W szczególności 'S zawiera a' i' S zawiera b' oznacza, że ​​'a

+0

Doskonale! To dużo bardziej zwięzłe niż moja wersja. –

+0

@rex Może byłby przydatny w zestawie z preorderem (http://en.wikipedia.org/wiki/Preorder). Wypowiedz drzewo redblack dla dostarczonego 'Ordering' z listami' HashSets' dla naturalnego uporządkowania/równoważności typu. Przynajmniej moja intuicja polegała na tym, że pod warunkiem, że "Zamawianie" będzie używane tylko do sortowania, a nie do szukania równoważności, nie wiem dlaczego. –

Powiązane problemy