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