Как я могу сгенерировать процент для соответствия строки регулярного выражения в Ruby?

Я пытаюсь создать простой метод, чтобы посмотреть около 100 записей в базе данных для фамилии и вытащить все те, которые соответствуют определенному проценту букв. Мой текущий подход:

  • Вытяните все 100 записей из базы данных в массив
  • Итерации через них при выполнении следующего действия
  • Разделить фамилию на массив букв
  • Вычтите этот массив из другого массива, который содержит буквы для имени, которое я пытаюсь сопоставить, которое оставляет только буквы, которые не были сопоставлены.
  • Возьмите размер результата и разделите его на исходный размер массива с шага 3, чтобы получить процент.
  • Если процент превышает предопределенный порог, нажмите этот объект базы данных в массив результатов.

Это работает, но я чувствую, что должен быть классный метод ruby ​​/regex/active record, чтобы сделать это более эффективно. Я немного искал Google, но ничего не могу найти.

Ответ 1

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

код

Сначала определите вспомогательный метод:

class Array
  def difference(other)
    h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
    reject { |e| h[e] > 0 && h[e] -= 1 }
  end
end

Короче говоря, если

a = [3,1,2,3,4,3,2,2,4]
b = [2,3,4,4,3,4]

затем

a - b           #=> [1]

тогда

a.difference(b) #=> [1, 3, 2, 2]

Этот метод разработан в моем ответе на этот вопрос SO. Я нашел так много применений, что я предложил добавить его в Ruby Core.

Следующий метод создает хеш, ключи которого являются элементами names (строки) и значениями которых являются доли букв в строке target, которые содержатся в каждой строке в names.

def target_fractions(names, target)
  target_arr = target.downcase.scan(/[a-z]/)
  target_size = target_arr.size
  names.each_with_object({}) do |s,h|
    s_arr = s.downcase.scan(/[a-z]/)
    target_remaining = target_arr.difference(s_arr)
    h[s] = (target_size-target_remaining.size)/target_size.to_f
  end
end

Пример

target = "Jimmy S. Bond"

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

names = ["Jill Dandy", "Boomer Asad", "Josefine Simbad"]

затем

target_fractions(names, target)
  #=> {"Jill Dandy"=>0.5, "Boomer Asad"=>0.5, "Josefine Simbad"=>0.8} 

Объяснение

Для приведенных выше значений names и target,

target_arr = target.downcase.scan(/[a-z]/)
  #=> ["j", "i", "m", "m", "y", "s", "b", "o", "n", "d"] 
target_size = target_arr.size
  #=> 10

Теперь рассмотрим

s = "Jill Dandy"
h = {}

затем

s_arr = s.downcase.scan(/[a-z]/)
  #=> ["j", "i", "l", "l", "d", "a", "n", "d", "y"]
target_remaining = target_arr.difference(s_arr)
  #=> ["m", "m", "s", "b", "o"]

h[s] = (target_size-target_remaining.size)/target_size.to_f
  #=> (10-5)/10.0 => 0.5
h #=> {"Jill Dandy"=>0.5}

Расчеты аналогичны для Бумера и Жозефина.