Как отсортировать по двум параметрам в OCL?

Мне нужно отсортировать коллекцию людей по двум параметрам: по фамилиям и по именам. Как я могу сделать что-то подобное в OCL?

3 ответа

Решение

sortedBy Функция сортирует элементы, используя критерии, выраженные в ее теле и < отношения между каждым собранным результатом.

В вашем случае, если у вас есть surname атрибут, следующий оператор будет сортировать коллекцию c с использованием < оператор на каждую фамилию набрал (так < по строкам):

c->sortedBy(p | p.surname)

Идея может состоять в том, чтобы вычислить уникальную строку, используя фамилию и объединенное имя вместе. Таким образом, если у вас есть:

  • Джордж Смит
  • Гарри Смит
  • Джордж Смат

Сравнение будет сделано между "Smith_George", "Smith_Garry" и "Smath_George" и будет выполнено в соответствии с лексикографическим порядком:

  1. Джордж Смат (Sm a th_George)
  2. Гарри Смит (Smith_G Rry)
  3. Джордж Смит (smith_G e orge)

Наконец, запрос OCL будет (при условии surname а также name как существующие атрибуты):

c->sortedBy(p | p.surname + '_' + p.name)

Этот маленький трюк делает свою работу, но это не "точное" сравнение двух параметров для sortedBy.

Спасибо, ты вдохновил меня. Я только что поднял http://issues.omg.org/browse/OCL25-213 чей текст:

Итерация sortedBy обеспечивает элегантное решение проблемы сортировки, в которой метрика сортировки является проекцией отсортированного объекта. Таким образом, sortedBy(p|p.name) или просто sortedBy(name) являются короткими и избегают возможностей для опечаток из более обычной экспозиции, включающей сравнение двух объектов. Естественное решение вполне может быть эффективным для больших коллекций с нетривиальными метриками.

Однако решение sortedBy незнакомо и так запутанно для новичков и непригодно для многоключевой сортировки, для которой может потребоваться создание искусственного составного одиночного ключа.

Одним из решений может быть предоставление более обычного итератора, такого как sort(p1, p2 | expression-expression), позволяющего сортировку по двум ключам:

sort(p1, p2 | let diff1 = p1.key1.compareTo (p2.key1), если diff1 <> 0, diff 1 else p1.key2.compareTo(p2.key2) endif)

Однако это имеет плохую читаемость и широкие возможности для опечаток.

В качестве альтернативы sortedBy с метрикой с кортежем может поддерживать несколько ключей:

sortedBy (Кортеж {первый = ключ1, второй = ключ2})

(Алфавитный порядок имен частей кортежа определяет приоритет.)

(Поскольку sortedBy декларативно понятен и компактен, неэффективные небольшие / тривиальные реализации могут быть оптимизированы до их эквивалентов sort().)

OCL sortedBy(лямбда), по-видимому, сильно отличается от сортировки Java (компаратор), очевидно, требующей проекции объектов в качестве метрики для сортировки. Однако, если проекция является собственной, у вас есть другая функциональность Java. Поэтому, если вы выполните sortedBy (p | p), сортировка зависит от операции <для p.

Чтобы облегчить это, прототип Eclipse OCL для будущего OCL представляет тип OclComparable с методом compareTo, позволяющим реализовать все реляционные операции при условии, что ваш пользовательский тип расширяет тип OclComparable.

(Подобный OclSummable с zero() и sum () работает в общем, поддерживает Collection::sum(); например, String реализует sum как конкатенацию.)

Другие вопросы по тегам