2012-03-15 12 views
6

tengo una lista de, digamos [gato, perro, vaca, caballo], que quiero ser ordenados de la siguiente maneraordenar una lista en maravilloso de una manera inusual

  • si el gato está en la lista debe venir primero
  • si Vaca está en la lista debe ser el segundo
  • El resto de los elementos debe venir después en orden alfabético.

¿Alguna sugerencia de cómo se puede hacer en groovy?

+1

Si Cow está en la lista y Cat no lo está, ¿la vaca todavía necesita estar en el segundo lugar? ¿Qué pasa si la lista es simplemente '['Cow']'? – ataylor

+0

No. Entonces la vaca debería ser la primera. – bladet

Respuesta

7

La respuesta de Tim es bastante inteligente. Personalmente soy más partidario de usar operaciones de lista ya que el código que genera es ligeramente más fácil de leer.

def highPriority = [ 'Cat', 'Cow' ] 

def list = [ 'Armadillo', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow', 'Cat' ] 

def remainder = (list - highPriority).sort() 

list.retainAll(highPriority) 

list.sort{ highPriority.indexOf(it) } + remainder 

Eso le dará vaca dos veces. Si no quiere duplicados, usar intersect es bastante simple.

def highPriority = [ 'Cat', 'Cow' ] 

def list = [ 'Armadillo', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow', 'Cat' ] 

list.intersect(highPriority).sort{ highPriority.indexOf(it) } + (list - highPriority).sort() 
+0

+1 Buena alternativa :-) –

+0

Estoy de acuerdo contigo Tomas. Como soy bastante nuevo en Groovy, su solución es más fácil de seguir. Gracias. – bladet

+0

@tomas: +1 a la respuesta excelente! –

6

Esto debe hacerlo:

// Define our input list 
def list = [ 'Armadillo', 'Cat', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow' ] 

// Define a closure that will do the sorting 
def sorter = { String a, String b, List prefixes=[ 'Cat', 'Cow' ] -> 
    // Get the index into order for a and b 
    // if not found, set to being Integer.MAX_VALUE 
    def (aidx,bidx) = [a,b].collect { prefixes.indexOf it }.collect { 
    it == -1 ? Integer.MAX_VALUE : it 
    } 
    // Compare the two indexes. 
    // If they are the same, compare alphabetically 
    aidx <=> bidx ?: a <=> b 
} 

// Create a new list by sorting using our closure 
def sorted = list.sort false, sorter 

// Print it out 
println sorted 

que imprime:

[Cat, Cow, Cow, Armadillo, Dog, Horse, Zebra] 

he comentado al tratar de explicar cada paso que se necesita. Mediante la adición de los elementos de prefijo por defecto como un parámetro opcional sobre el cierre sorter, significa que podemos hacer cosas como esta para cambiar el valor por defecto:

// Use Dog, Zebra, Cow as our prefix items 
def dzc = list.sort false, sorter.rcurry([ 'Dog', 'Zebra', 'Cow' ]) 
println dzc 

Que luego imprime la lista clasificada como:

[Dog, Zebra, Cow, Cow, Armadillo, Cat, Horse] 
0

Si usted no tiene elementos duplicados, puede intentar esto:

def highPriority = [ 'Cat', 'Cow' ] 
def list = [ 'Armadillo', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cat' ] 
highPriority + list.minus(highPriority).sort() 
+0

¿Qué pasa si falta Cat en la lista? –

0

inspirada en tomas' answer:

def highPriority = [ 'Cat', 'Cow' ] 
def list = [ 'Armadillo', 'Cat', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow' ] 

// Group animals by priority. 
def groups = list.groupBy { it in highPriority ? it : 'rest' } 
// High priority animals are sorted by priority and the rest alphabetically. 
def sorted = highPriority.collectMany { groups[it] } + groups['rest'].sort() 

assert sorted == ['Cat', 'Cow', 'Cow', 'Armadillo', 'Dog', 'Horse', 'Zebra'] 

La variable groups es algo así como [rest:[Armadillo, Dog, Zebra, Horse], Cat:[Cat], Cow:[Cow, Cow]].

Otro, posiblemente menos robusto, solución podría ser:

def sorted = list.sort(false) { 
    def priority = highPriority.indexOf(it) 
    if (priority == -1) priority = highPriority.size() 
    // Sort first by priority and then by the value itself 
    "$priority$it" 
} 

es menos robusto en el sentido de que se ordena por cadenas como "2Armadillo", "0Cat", etc, y no funcionará si tiene 9 o más animales de alta prioridad (porque "10Alpaca" < "9Eel". sería genial si Groovy proporciona algún tipo de tipo tupla comparables, como Python's tuples, así que en vez de volver "$priority$it" como la clave comparables, se podría devolver la tupla (priority, it).

1

Aquí hay otra alternativa que se siente más simple para mí:

// smaller values get sorted first 
def priority(animal) { 
    animal in ['Cat', 'Cow'] ? 0 : 1 
} 

def list = [ 'Armadillo', 'Cat', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow' ] 

def sorted = list.sort{ a, b -> priority(a) <=> priority(b) ?: a <=> b } 

assert sorted == ['Cat', 'Cow', 'Cow', 'Armadillo', 'Dog', 'Horse', 'Zebra'] 
+0

¿Qué sucede si quiere Cow in Cat en su lista de prioridades? ;) –

+0

Dar vaca prioridad 0, Cat prioridad 1, todo lo demás prioridad 2. – ataylor

+0

En groovy: '[Vaca: 0, Gato: 1] .withDefault {2} [animal]' :) – ataylor

0

Esta pregunta es bastante viejo, pero hoy he descubierto que maravilloso tiene una, en lugar indocumentado OrderBy comparador, que se puede utilizar en este caso:

def highPriority = ['Cow', 'Cat'] 
def list = ['Armadillo', 'Cat', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow'] 

def sorted = list.sort new OrderBy([{ -highPriority.indexOf(it) }, { it }]) 

assert sorted == ['Cat', 'Cow', 'Cow', 'Armadillo', 'Dog', 'Horse', 'Zebra'] 

el comparador OrderBy primero compara los animales utilizando su índice en la lista highPriority negadas (por lo tanto los animales que no son de alta prioridad (es decir, índice -1) se mueven a la parte posterior de la lista) y si los índices son iguales, los compara con la función de identidad {it}, que, como los animales son cadenas, los ordena alfabéticamente.

Cuestiones relacionadas