2012-03-15 31 views
6

mam listę, powiedzmy [kot, pies, krowa, koń], że chcę być sortowane w następujący sposóbsortowanie listy w Groovy w niezwykły sposób

  • jeśli kot jest w lista powinna być pierwsza
  • , jeśli krowa jest na liście, powinna być druga.
  • Reszta elementów powinna pochodzić w kolejności alfabetycznej.

Jakieś sugestie, w jaki sposób można to zrobić w sposób groovy?

+1

Jeśli na liście jest krowa, a kot nie, czy krowa nadal musi znajdować się na drugim miejscu? Co jeśli lista jest po prostu '['Krowa']'? – ataylor

+0

Nie. Wtedy krowa powinna być pierwsza. – bladet

Odpowiedz

7

Odpowiedź Tima jest dość sprytna. Osobiście jestem bardziej fanem korzystania z operacji na liście, ponieważ kod, który generuje, jest nieco łatwiejszy do odczytania.

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 

To da ci Krowa dwukrotnie. Jeśli nie chcesz duplikatów, używanie przecięcia jest dość proste.

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 Dobra alternatywa :-) –

+0

Zgadzam się z Tobą Tomas. Odkąd jestem całkiem nowy na groovy, twoje rozwiązanie jest łatwiejsze do naśladowania. Dzięki. – bladet

+0

@ tomas: +1 za doskonałą odpowiedź! –

6

ten powinien zrobić:

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

która drukuje:

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

mam skomentował to, aby spróbować wyjaśnić każdy krok potrzebny. Dodając elementy domyślny prefiks jako opcjonalny parametr w sprawie zamknięcia sorter, oznacza to możemy robić rzeczy, tak aby zmienić domyślną:

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

Które następnie drukuje listę posortowaną jak:

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

Jeśli nie masz zduplikowane elementy, można spróbować to:

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

Co zrobić, jeśli kota brakuje na liście? –

0

inspirowany 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'] 

Zmienna groups jest coś takiego jak [rest:[Armadillo, Dog, Zebra, Horse], Cat:[Cat], Cow:[Cow, Cow]].

innego, prawdopodobnie mniej wytrzymałe, rozwiązaniem może być:

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

Jest mniej wytrzymałe w tym sensie, że sortuje ciągi jak "2Armadillo", "0Cat", itp, i nie będzie działać, jeśli masz 9 lub więcej zwierząt o wysokim priorytecie (ponieważ "10Alpaca" < "9Eel". Byłoby fajnie, gdyby Groovy dostarczył jakiś porównywalny typ krotki, taki jak Python's tuples, więc zamiast zwracać "$priority$it" jako klucz porównywalny, można zwrócić krotkę (priority, it).

1

Oto kolejna alternatywa, która czuje się prostsze do mnie:

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

Co się stanie, jeśli chcesz, aby Krowa przed Kotem znajdowała się na twojej liście priorytetów? ;) –

+0

Daj krowie priorytet 0, Priorytet kota 1, wszystko inne priorytet 2. – ataylor

+0

W groovy: '[Krowa: 0, Kot: 1] .withDefault {2} [zwierzę]' :) – ataylor

0

To pytanie jest dość stary, ale dzisiaj uważam, że Groovy ma raczej nieudokumentowane, OrderBy porównawczy, który można wykorzystać w tym przypadku:

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'] 

OrderBy komparator porównuje pierwszą zwierzętom stosując indeksie liście highPriority negowane (dlatego zwierzęta nie są w wysokim priorytetem (indeks 1) są przesuwane do tyłu z listy) i jeśli indeksy są równe, porównuje je przez funkcję tożsamości {it}, która, jak zwierzęta są ciągami, sortuje je alfabetycznie.

Powiązane problemy