2012-03-15 13 views
6

ho una lista di, consente di dire [gatto, cane, mucca, cavallo], che voglio da ordinare nel modo seguenteordinamento di un elenco in Groovy in modo insolito

  • se Cat è in la lista dovrebbe venire prima
  • se la Mucca è nella lista dovrebbe venire il secondo
  • Il resto degli elementi dovrebbe venire dopo in ordine alfabetico.

Qualche suggerimento su come questo potrebbe essere fatto in Groovy?

+1

Se la mucca è nella lista e Cat non lo è, la mucca deve ancora essere al secondo posto? Cosa succede se la lista è solo '['Cow']'? – ataylor

+0

No. Allora la mucca dovrebbe essere la prima. – bladet

risposta

7

La risposta di Tim è abbastanza intelligente. Personalmente sono più un fan del solo utilizzo delle operazioni di lista in quanto il codice che genera è leggermente più facile da leggere.

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 

Che vi darà due volte Cow. Se non vuoi duplicati, l'uso di intersect è abbastanza semplice.

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 Bella alternativa :-) –

+0

Sono d'accordo con te Tomas. Dato che sono abbastanza nuovo da entusiasmare, la tua soluzione è più facile da seguire. Grazie. – bladet

+0

@tomas: +1 per una risposta eccellente! –

6

Questo dovrebbe farlo:

// 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 

che le stampe:

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

Ho commentato a cercare di spiegare ogni passaggio che ci vuole. Aggiungendo gli elementi prefisso predefinito come parametro opzionale sulla chiusura sorter, significa che siamo in grado di fare cose come questa per modificare l'impostazione predefinita:

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

che stamperà l'elenco ordinato come:

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

Se non si dispone di elementi duplicati, si può provare questo:

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

Cosa succede se Cat manca dalla lista? –

0

ispirato 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 variabile groups è qualcosa di simile [rest:[Armadillo, Dog, Zebra, Horse], Cat:[Cat], Cow:[Cow, Cow]].

Un altro, forse meno robusta, la soluzione potrebbe essere:

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

è meno robusto nel senso che ordina da stringhe come "2Armadillo", "0Cat", ecc, e non funzionerà se si dispone di 9 o più animali ad alta priorità (perché "10Alpaca" < "9Eel". Sarebbe bello se Groovy fornisse una specie di tipo di tupla simile, come Python's tuples, quindi invece di restituire "$priority$it" come chiave comparabile, si potrebbe restituire la tupla (priority, it).

1

Ecco un'altra alternativa che si sente più semplice per me:

// 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

Cosa succede se vuoi Cow prima di Cat nell'elenco delle priorità? ;) –

+0

Dare priorità mucca 0, priorità gatto 1, qualsiasi altra priorità 2. – ataylor

+0

In groovy: '[Mucca: 0, Cat: 1] .withDefault {2} [animale]' :) – ataylor

0

Questa domanda è piuttosto vecchio, ma oggi ho scoperto che Groovy ha una, piuttosto non documentata, OrderBy comparatore che può essere utilizzato in questo 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'] 

il OrderBy comparatore confronta primo gli animali con il loro indice nell'elenco highPriority negati (quindi gli animali che non sono alta priorità (ad esempio index -1) vengono spostati sul retro della lista) e se gli indici sono uguali li confronta con la funzione di identità {it}, che, come animali sono stringhe, li ordina alfabeticamente.

Problemi correlati