сравнение хешей со строками в ruby - PullRequest
0 голосов
/ 03 февраля 2020

Я пытаюсь сделать что-то вроде анализатора строк, и мне нужно получить окончание слова и сравнить его с ключами га sh

word = "Test"
ending_hash = {"e" => 1, "st" => 2}
output = 2

Мне нужен вывод быть 2 в этом случае, но на самом деле я не буду знать, если длина окончания составляет 1 или 2 символа. Можно ли это сделать?

Ответы [ 2 ]

2 голосов
/ 03 февраля 2020

Сначала предположим, что вы знаете, что word заканчивается (как минимум) одним из ключей ending_hash. Затем вы можете написать:

word = "Test"
ending_hash = {"e" => 1, "st" => 2}

ending_hash.find { |k,v| word.end_with?(k) }.last
  #=> 2

См. Enumerable # find , Строка # end_with? и Массив # последний .

Промежуточный расчет выглядит следующим образом:

ending_hash.find { |k,v| word.end_with?(k) }
  #=> ["st", 2]

Если вы не уверены, могут ли совпадать любые клавиш в конце строки напишите:

ending_hash = {"e" => 1, "f" => 2} 
arr = ending_hash.find { |k,v| word.end_with?(k) }
  #=> nil
arr.nil? ? nil : arr.last
  #=> nil

или лучше:

ending_hash.find { |k,v| word.end_with?(k) }&.last
  #=> nil

Здесь & - это Оператор безопасной навигации . В двух словах, если выражение, предшествующее &, возвращает nil, SNO немедленно возвращает nil для всего выражения без выполнения last.

, даже если word должен заканчиваться одним из ключи, вы можете написать это таким образом, чтобы вы могли проверить возвращаемое значение и вызвать исключение, если оно nil.

Вы можете альтернативно написать:

ending_hash.find { |k,v| word.match? /#{k}\z/ }&.last

Регулярное выражение гласит: «соответствует значение из k (#{k}) в конце строки (якорь \z)».

Обратите внимание на следующее:

{"t"=>1, "st"=>2}.find { |k,v| word.end_with?(k) }&.last
  #=> 1
{"st"=>1, "t"=>2}.find { |k,v| word.end_with?(k) }&.last
  #=> 1

, поэтому порядок ключей может иметь значение.

Наконец, поскольку блочная переменная v не используется в расчете блока, переменные блока часто записываются |k,_| или |k,_v|, главным образом, чтобы сообщить читателю, что только k используется в расчете блока.

0 голосов
/ 04 февраля 2020

Если вы знаете, что будет только небольшое количество длин концов, гораздо быстрее проверить все возможные длины, чем проверить все окончания. (Также имеет смысл проверять их от самого длинного до самого короткого, если они перекрываются, иначе короткое никогда не будет сопоставлено.)

Ленивый однострочный:

(-2..-1).lazy.map { |cut| ending_hash[word[cut..]] }.find(&:itself)

Функциональный версия:

(-2..-1).inject(nil) { |a, e| a || ending_hash[word[e..]] }

Тупая, но влажная версия:

ending_hash[word[-2..]] || ending_hash[word[-1..]]
...