Сортировка списка в Groovy необычным способом - PullRequest
8 голосов
/ 15 марта 2012

У меня есть список, скажем, [Cat, Dog, Cow, Horse], который я хочу отсортировать следующим образом

  • если Cat находится в списке, он должен стоять первым
  • если Cow находится в списке, он должен идти вторым
  • Остальные элементы должны следовать в алфавитном порядке.

Есть предложения, как это можно сделать в Groovy?

Ответы [ 6 ]

7 голосов
/ 15 марта 2012

Ответ Тима довольно умный. Лично я больше фанат использования операций со списками, так как генерируемый им код легче читать.

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

Это даст тебе Корову дважды. Если вам не нужны дубликаты, использовать пересечение довольно просто.

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

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

list.intersect( highPriority ).sort{ highPriority.indexOf( it ) } + ( list - highPriority ).sort()
6 голосов
/ 15 марта 2012

Это должно сделать это:

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

Это печатает:

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

Я прокомментировал это, чтобы попытаться объяснить каждый шаг, который он предпринимает. Добавление элементов префикса по умолчанию в качестве необязательного параметра к закрытию sorter означает, что мы можем сделать что-то подобное, чтобы изменить значение по умолчанию:

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

Который затем печатает список, отсортированный как:

[Dog, Zebra, Cow, Cow, Armadillo, Cat, Horse]
2 голосов
/ 15 марта 2012

Вот еще одна альтернатива, которая мне кажется проще:

// 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']
1 голос
/ 15 марта 2012

Если у вас нет повторяющихся элементов, вы можете попробовать это:

def highPriority = [ 'Cat', 'Cow' ]
def list = [ 'Armadillo', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cat' ]
highPriority + list.minus(highPriority).sort()
0 голосов
/ 23 мая 2012

Этот вопрос довольно старый, но сегодня я обнаружил, что в Groovy есть довольно недокументированный компаратор OrderBy, который можно использовать в этом случае:

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 сначала сравнивает животных, используя их индекс в отрицательном списке highPriority (поэтому животные, которые не имеют высокого приоритета (т.е. индекс -1), перемещаются в конец списка), и если индексы равны, он сравнивает их по тождественной функции {it}, которая, поскольку животные являются строками, сортирует их по алфавиту.

0 голосов
/ 15 марта 2012

Вдохновленный на ответ Томаса :

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

Переменная groups выглядит примерно так: [rest:[Armadillo, Dog, Zebra, Horse], Cat:[Cat], Cow:[Cow, Cow]].

Другое, возможно, менее надежное решение можетbe:

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

Он менее надежен в том смысле, что сортирует по строкам, таким как "2Armadillo", "0Cat" и т. д., и не будет работать, если у вас 9 или более животных с высоким приоритетом (потому что"10Alpaca" < "9Eel". Было бы здорово, если бы Groovy предоставил какой-то сопоставимый тип кортежа, например кортежи Python , поэтому вместо возврата "$priority$it" в качестве сопоставимого ключа можно было бы вернуть кортеж (priority, it).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...