Сортировка списка в Groovy необычным способом
У меня есть список, скажем [Cat, Dog, Cow, Horse], который я хочу отсортировать следующим образом
- если
Catесть в списке, то он должен быть первым - если
Cowесть в списке, он должен быть вторым
Остальные элементы должны следовать в алфавитном порядке.
Есть предложения, как это можно сделать в Groovy?
6 ответов:
Ответ Тима довольно умен. Лично я больше люблю просто использовать операции со списком, поскольку код, который он генерирует, немного легче читать.
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Это даст вам корову дважды. Если вы не хотите дубликатов, использование intersect довольно просто.
def highPriority = [ 'Cat', 'Cow' ] def list = [ 'Armadillo', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow', 'Cat' ] list.intersect( highPriority ).sort{ highPriority.indexOf( it ) } + ( list - highPriority ).sort()
Это должно сделать:
// 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]
Если у вас нет дубликатов элементов, вы можете попробовать следующее:
def highPriority = [ 'Cat', 'Cow' ] def list = [ 'Armadillo', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cat' ] highPriority + list.minus(highPriority).sort()
Вот еще одна альтернатива, которая кажется мне проще:
// 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']
Вдохновленный ответом Томаса :
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]].Другим, возможно менее надежным, решением может быть:
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's tuples , поэтому вместо возврата"$priority$it"в качестве сопоставимого ключ, можно было бы вернуть кортеж(priority, it).
Этот вопрос довольно стар, но сегодня я обнаружил, что у 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}, которая, поскольку животные являются строками, сортирует их по алфавиту.
Comments