Как отсортировать список по существующим свойствам - PullRequest
9 голосов
/ 05 марта 2012

Я использую эту строку здесь для сортировки списка на основе имени объекта.

g.V.sort{it.name}

Как мне отсортировать его по «имени», если оно существует, если нет, я хочу отсортировать его по"заглавие".Если оба существуют, я хочу сначала отсортировать по «имени», а затем по «названию».

Я не Groovy-кодер, поэтому заранее спасибо за помощь.

Ответы [ 3 ]

13 голосов
/ 05 марта 2012

Я не уверен, что правильно понял ваш вопрос. Может быть, это то, что вы ищете:

def things = [
    [name: 'aaa', title: '222'],
    [name: 'aaa', title: '333'],
    [title: '222'],
    [title: '111'],
    [name: 'bbb', title: '111'],
    [title: '333'],
    [name: 'aaa', title: '111'],
]

things.sort { a, b ->
    // Compare by name and then by title.
    a.name <=> b.name ?: a.title <=> b.title
}

assert things == [
    [title: '111'],
    [title: '222'],
    [title: '333'],
    [name: 'aaa', title: '111'],
    [name: 'aaa', title: '222'],
    [name: 'aaa', title: '333'],
    [name: 'bbb', title: '111'],
]

То, что происходит внутри этой, казалось бы, невинной функции сравнения, на самом деле является довольно сильной магией синтаксиса Groovy. Но за этим не так уж сложно следить.

Во-первых, метод sort вызывается с двоичной функцией, которая действует как компаратор (т.е. принимает два аргумента, a и b, и возвращает -1, если a b и 0, если a == b).

Эта анонимная функция: { a, b -> a.name <=> b.name ?: a.title <=> b.title } использует " оператор космического корабля " (<=> ... это человек из космического корабля!), Чтобы сначала сравнить a и b по именам.

Если имена равны (или оба равны нулю), то результат a.name <=> b.name равен 0, что ложно оценивается в " Операторе Элвиса " (?: ... представить его как смайлик), значит, результат a.title <=> b.title возвращается.

В противном случае, если результат сравнения имен не равен 0, тогда это верно оценивается в операторе Элвиса, и это значение возвращается.

Это все с учетом того, что вы можете сравнивать нулевые значения со строками и что 'any string' > null всегда выполняется (то же самое, что сказать, что 'any string' <=> null == 1).

Таким образом, окончательный результат состоит в том, что элементы без имени сначала сортируются по заголовку, а затем элементы с именем и заголовком упорядочиваются сначала по имени, а затем по заголовку.

Надеюсь, это было то, что вы искали. Если вы ожидали другого упорядочения отсортированных элементов, не стесняйтесь уточнить это в комментариях:)

Обновление

Существует также не очень документированный OrderBy объект, который можно использовать в этом случае:

things.sort new OrderBy([{it.name}, {it.title}])
5 голосов
/ 05 марта 2012

Вы можете отсортировать коллекцию, используя Comparator.

g.V.sort { a, b ->
    a.name <=> b.name ?: a.title <=> b.title
}
0 голосов
/ 05 марта 2012

Это мое полностью неопробованное усилие, которое, вероятно, пронизано ошибками

def comparator = {o1, o2 ->

  // wording of question suggests title will always exist, if not, add more hasProperty checks  
  def diff = o1.title <=> o2.title

  if (o1.hasProperty('name') && o2.hasProperty('name')) {  
    def nameDiff = o1.name <=> o2.name

    if (nameDiff != 0) {
      diff = nameDiff
    }
  } 
  diff

} as Comparator


def someList = []
// populate the list...    
someList.sort(comparator)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...