Сортировка значений с использованием определенного сопоставления в Ruby / Rails - PullRequest
12 голосов
/ 29 марта 2011

Можно ли отсортировать массив значений с использованием определенного сопоставления в Ruby? У меня есть необходимость сортировать в соответствии с сортировкой da_DK.

Учитывая массив %w(Aarhus Aalborg Assens) Я хотел бы получить ['Assens', 'Aalborg', 'Aarhus'] назад, что является правильным порядком на датском.

Стандартный метод сортировки

%w(Aarhus Aalborg Assens).sort

возвращает что-то похожее на порядок ascii (по крайней мере, не на датский):

["Aalborg", "Aarhus", "Assens"]

В среде Snow Leopard и Linux работает ruby ​​1.9.2 и Rails 3.0.5.

Ответы [ 2 ]

6 голосов
/ 29 марта 2011

Согласно Википедии :

В датском и норвежском алфавитах присутствуют те же дополнительные гласные, что и в шведском (см. Ниже), но в другом порядке и сразные символы (..., X, Y, Z, Æ, Ø, Å).Кроме того, «Aa» сопоставляется как эквивалент «Å».Датский алфавит традиционно рассматривал букву "W" как вариант буквы "V", но сегодня буква "W" считается отдельной буквой. "

Это исключит сортировку.

Сделайте это, чтобы решить проблему:

names = %w(Aarhus Aalborg Assens)
names.sort_by { |w| w.gsub('Aa', 'Å') } # => ["Assens", "Aalborg", "Aarhus"]

и что-то подобное для других букв, у которых есть составные комбинации символов для преобразования в один символ.

Причина, по которой это работает, sort_by делает Преобразование Шварца , так что это на самом деле сортировка по возвращаемому значению, возвращенному из блока, который, в данном случае, является именем с «Aa», замененным на «Å». Замена является временной и отбрасывается, когдамассив отсортирован.

sort_by очень мощный, но имеет некоторые издержки. Для простой сортировки вы должны использовать sort, потому что он быстрее. Для сортировок, где вы сравниваете два простых значения весли вы используете sort или sort_by. Если вам нужно делать более сложные вычисления или копаться в объекте, тогда sort_by можетРоув, чтобы быть быстрее.Нет точного и быстрого способа узнать, что лучше, поэтому я настоятельно рекомендую тестировать с помощью эталонного теста, если вам нужно сортировать большие массивы или иметь дело с объектами, потому что разница может быть большой, а иногда sort можетбудь лучшим выбором.

РЕДАКТИРОВАТЬ:

Руби сама по себе не собирается делать то, что вы хотите, потому что она не знает порядка сортировки каждого установленного там символа.Существует обсуждение относительно включения ICU IBM , которое объясняет, почему это так.Если вы хотите способности ICU, вы можете посмотреть ICU4R .Я не играл с этим, но это звучит как ваше единственное реальное решение в Ruby.

Возможно, вы сможете что-то сделать с базой данных, такой как Postgres.Они поддерживают различные параметры сортировки, но обычно вынуждают вас объявлять параметры сортировки при создании базы данных ... или, может быть, это когда таблица создается ... прошло много времени с тех пор, как я создал новую таблицу.Во всяком случае, это был бы вариант, хотя это было бы боль.

4 голосов
/ 29 марта 2011

Я нашел ffi-locale на Github, и это решает мою проблему, насколько я вижу.

Позволяет следующий код:

FFILocale::setlocale FFILocale::LC_COLLATE, 'da_DK.UTF-8'
%w(Aarhus Aalborg Assens).sort { |a,b| FFILocale::strcoll(a, b) }

, который возвращает правильный результат:

=> ["Assens", "Aalborg", "Aarhus"]

Я еще не исследовал производительность, но он обращается к собственному коду, поэтому он должен быть быстрее, чем код замены символов Ruby ...

Обновление
Это не идеально :( Это не работает должным образом на Snow Leopard - кажется, что функция strcoll не работает на OS X и была в течение некоторого времени. Это раздражает меня, но основной платформой для развертывания является linux - там, где она работает - так что это мое предпочтительное решение.

...