Сортировка значений с использованием определенной сортировки в Ruby/Rails

Можно ли отсортировать массив значений, используя определенную сортировку в Ruby? Мне нужно сортировать в соответствии с настройкой da_DK.

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

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

%w(Aarhus Aalborg Assens).sort

возвращает то, что выглядит как порядок ascii (по крайней мере, не датский порядок):

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

Среда - это Snow Leopard и linux run ruby ​​1.9.2 и Rails 3.0.5.

Ответы

Ответ 1

Я нашел 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...

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

Ответ 2

Согласно Wikipedia:

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

Это отбросит сортировку.

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

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

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

Причина, по которой это работает, sort_by делает Schwartzian Transformation, поэтому она фактически сортирует по возвращаемому значению, возвращенному из блока, что, в этом случае это имя с заменой "Aa" на "Å". Замена является временной и отбрасывается при сортировке массива.

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

EDIT:

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

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