2011-02-10 14 views
9

Digamos que tengo un conjunto de cadenas que quiero que sean ordenadas por longitud pero únicas por la singularidad normal de String. Lo que quiero decir es que puedo tener más de una cadena de la misma longitud en el Set, pero que deben ordenarse por longitud.Scala SortedSet - ordenado por un pedido y único por otra cosa?

Quiero expresar el ordenamiento de esta manera:

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

que creo que se ve muy bien. Pero si tuviera que tirar esto en un SortedSet, dicen así:

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

solo me dan 'bar'. Esto se debe a que el Ordering representa un pedido total y, por lo tanto, cuando compare devuelve 0, los elementos se consideran idénticos.

Por lo tanto, estoy pensando que necesito hacer un pedido encadenado y comparar las cadenas si las longitudes son iguales. Para ello he utilizado el -pattern "Pimp mi biblioteca" de esta manera:

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

que puedo utilizar como:

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

me pareció que estaba muy bien, pero luego me di cuenta de que lo que quería hacer no era realmente ordenar por el orden natural de Strings, solo quería ordenar por tamaño, pero la singularidad por otra cosa. ¿Es esto posible de una manera más elegante?

Respuesta

18

Lo que hago en este tipo de situaciones es la siguiente:

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

En otras palabras, usar una tupla para obtener un desempate.

Por otro lado, creo que es tonto de SortedSet considerar elementos de la misma en función de su que ordena. Creo que esto se ha discutido antes, pero no descartaría la posibilidad de buscar archivos de listas de correo y el scala trac para discusiones/tickets sobre esto, y tal vez intentar obtener SortedSet para cambiar su comportamiento.

+4

Un conjunto solo contiene objetos distintos. Un conjunto ordenado tiene un orden total. En particular, 'S contiene a' y' S contiene b' significa que ya sea 'a

+0

¡Excelente! Eso es mucho más conciso que mi versión. –

+0

@rex Tal vez sería útil con un conjunto preordenado (http://en.wikipedia.org/wiki/Preorder). Diga un árbol redblack para el 'Ordering' provisto con hojas de' HashSets' para el orden/equivalencia natural del tipo. Al menos mi intuición fue que el 'Ordering' provisto solo se usaría para ordenar y no buscar la equivalencia, no sé por qué. –

Cuestiones relacionadas