Как я могу отсортировать массив строк на основе нестандартного алфавита?

Я пытаюсь отсортировать массив фраз на эсперанто в алфавитном порядке. Есть ли способ использовать sort_by для этого?

Я проверяю каждый символ строки по его индексу в эсперанто-алфавите, причем каждый увеличивающийся индекс на шаг ниже в приоритете сортировки:

  esp_alph = " abcĉdefgĝhĥijĵklmnoprsŝtuŭvz"
  arr.sort_by {|string|  
    [esp_alph.index(string[0]),
     esp_alph.index(string[1]),
     esp_alph.index(string[2]),
     esp_alph.index(string[3])]}

Однако это не масштабируемое решение, и оно ломается, если у меня больше условий, чем символов в строке. Кажется, я нахожусь прямо на пороге цикла, основанного на длине моей строки, но я не могу понять, как это реализовать без синтаксических ошибок. Или есть лучший способ решить эту проблему?


person sammms    schedule 03.03.2016    source источник
comment
Ваш код недействителен. Что делает end?   -  person sawa    schedule 03.03.2016
comment
Непонятно, что вы имеете в виду, если у меня больше условий, чем символов в моей строке.   -  person sawa    schedule 03.03.2016
comment
Спасибо, что указали на этот «конец», он остался от документа, из которого я это скопировал. Что я имею в виду под большим количеством условий, чем символов, так это; В моем блоке sort_by каждый символ проверяется отдельной строкой кода, чтобы найти его индекс относительно строки esp_alph. поэтому, если у меня есть строка abcd и четыре строки, описывающие каждый из этих символов с точки зрения их местоположения в строке esp_alph, блок работает. Однако, если я запускаю блок на строке abc, он ломается, потому что строка esp_alph.index(string[3]) проверяет 'nil'. Состояние было не то слово, спасибо.   -  person sammms    schedule 03.03.2016


Ответы (3)


Просто замените все символы в алфавите эсперанто некоторыми символами в таблице ASCII, чтобы порядок в алфавите эсперанто совпадал с порядком в ASCII.

Предположим, у вас есть алфавиты эсперанто в указанном вами порядке, который, как я предполагаю, находится в том порядке, в котором они должны быть:

esp_alph = " abcĉdefgĝhĥijĵklmnoprsŝtuŭvz"

и удалите любую часть таблицы символов ASCII той же длины (обратите внимание, что \\ — это один символ):

ascii = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\"

or

ascii = "@-\\"

Затем вы можете просто сделать:

arr.sort_by{|string| string.tr(esp_alph, ascii)}

Здесь tr быстрее, чем gsub, и я думаю, что он достаточно масштабируется.

person sawa    schedule 03.03.2016
comment
Это не удается при объединении диакритических знаков. - person Aleksei Matiushkin; 03.03.2016
comment
@mudasobwa Разве они не выражены одним символом каждый? Думаю, в Ruby › 1.9, который обрабатывает многобайтовые символы, это работает. - person sawa; 03.03.2016
comment
"ĉ".codepoints #⇒ [265], а "c\u0302".codepoints #⇒ [99, 770]. Тем не менее мне нравится такой подход. Комбинированные диакритические знаки должны быть преобразованы в прежние латинские1 или наоборот перед обработкой. - person Aleksei Matiushkin; 03.03.2016
comment
Они не просто многобайтовые. Это множественные кодовые точки. - person Aleksei Matiushkin; 03.03.2016
comment
@mudasobwa Но разве в примере ОП нет одиночных символов кода? - person sawa; 03.03.2016
comment
Ну, технически мы не можем различить "ĉ" и "c\u0302", глядя на него :) В примере OP иногда использовались символы с одной кодовой точкой. да. Но умные люди могут настроить клавиатуру (я сделал это для одновременного использования испанского - и немецкого ä акцентов). В любом случае, я проголосовал за это решение, поскольку на самом деле а) никто, кроме меня, не заботится об этих двух разных представлениях акцентов и б) это решение может легко обновлять для обработки комбинированных диакритических знаков. - person Aleksei Matiushkin; 03.03.2016
comment
Фантастика, спасибо. Я все еще не понимаю механику того, как это работает, но это то, что нужно продолжать, я ценю это! - person sammms; 03.03.2016

esp_alph = " abcĉĉdefgĝĝhĥĥijĵĵklmnoprsŝŝtuŭŭvz"

arr = ["abc\u0302a", "abĉa","abca" ]
p arr.sort_by {|string| string.chars.map{|c| esp_alph.index(c)}}
# => ["abca", "abĉa", "abĉa"]

Возможно, для лучшей производительности строка esp_alph должна быть хешем.

person steenslag    schedule 03.03.2016
comment
Это не работает с комбинированными диакритическими знаками. Это не так просто. - person Aleksei Matiushkin; 03.03.2016
comment
@mudasobwa у тебя есть пример? - person steenslag; 03.03.2016
comment
"abc\u0302", "abu\u0306" и т. д. - person Aleksei Matiushkin; 03.03.2016
comment
@mudasobwa Спасибо. Код адаптирован. - person steenslag; 03.03.2016
comment
Правило 73: за chars следует метод Array, за each_char следует метод Enumerable, причем последний позволяет избежать создания ненужного временного массива. - person Cary Swoveland; 04.03.2016

person    schedule
comment
@mudasobwa, в ожидании вашего комментария, я думаю, можно было бы справиться с диакритическими знаками, определив ESP_ALPH как массив символов и соответствующим образом изменив остальные (например, удалив как .each_char, так и .char.) Да? - person Cary Swoveland; 04.03.2016