Как разработчик, в основном интерфейсный, это область компьютерных наук, в которую я не часто вникаю, но вот мой сценарий:
У меня есть ввод строки, splitна пробелах, скажем, "pinto beans"
У меня есть массив результатов для поиска, который содержит такие результаты, как: ["beans, mung","beans, pinto","beans, yellow","beans, fava"]
, что может быть самым быстрым способом (предпочтительно в JavaScript или PHP), чтобы найти наиболее «релевантные» результаты, то есть большинство совпадений, например, в приведенном выше случае, я хотел бы отсортировать возвращаемый массив так, чтобы "beans, pinto"
ставился вверху, а остальные - ниже, а все остальныерезультаты будут ниже этих.
Моей первой попыткой было бы сделать что-то вроде сопоставления каждого элемента результата с каждым входным элементом и увеличения совпадений для каждого, а затем сортировки по большинству совпадений с наименьшим.
Этот подход потребовал бы от меня повторения по всему массиву результатов много раз, и я чувствую, что мое отсутствие знаний по CS оставляет меня без лучшего решения здесь.
/ * РЕДАКТИРОВАТЬ: Вот как я закончил с этой проблемой: * /
Основываясь на предложении crazedfred и сообщении в блоге, которое он упомянул (что было ОЧЕНЬ полезно), я написал несколько php, которые в основном используют комбинацию изметод три и метод Бойера-Мура, кроме поиска в начале строки (поскольку я не хочу сопоставлять "bean" в "superbean").
Я выбрал php для ранжирования на основеТот факт, что я использую библиотеки js и получаю реальные тесты при использовании вспомогательных функций и издержек на библиотеку, не даст результатов, которые мне нужны, и я не могу гарантировать, что они не взорвутся в том или ином браузере.
Вот тестовые данные:
Строка поиска: lima beans
Массив результатов (из дБ): ["Beans, kidney","Beans, lima","Beans, navy","Beans, pinto","Beans, shellie","Beans, snap","Beans, mung","Beans, fava","Beans, adzuki","Beans, baked","Beans, black","Beans, black turtle soup","Beans, cranberry (roman)","Beans, french","Beans, great northern","Beans, pink","Beans, small white","Beans, yellow","Beans, white","Beans, chili","Beans, liquid from stewed kidney beans","Stew, pinto bean and hominy"]
Сначала я отбрасываю обастроку поиска и массив результатов в переменные php, после explode()
строки в пробелах.
затем я прекомпилирую свои шаблоны для сравнения результатов с:
$max = max(array_map('strlen',$input));
$reg = array();
for($m = 0; $m < $max; $m++) {
$reg[$m] = "";
for($ia = 0; $ia < count($input); $ia++) {
$reg[$m]. = $input[$ia][$m];
}
}
это даетмне что-нибудьНапример: ["lb","ie","ma","an","s"]
Затем я в основном беру каждую строку результата (разбитую на пробелы) и сопоставляю ей класс символов без учета регистра с соответствующим номером символа.Если в какой-то момент в процессе сравнения я не нашел совпадений, я пропускаю слово.Это означает, что если только 1 результат начинается с «b» или «l», я буду выполнять только одно сравнение на WORD, что действительно быстро.По сути, я беру на себя часть trie, которая собирает результаты поиска вместе, и постоянное ускорение работы Бойера-Мура.
Вот php - я пробовал while
s, но получил ЗНАЧИТЕЛЬНО лучшие результаты с foreach
es:
$sort = array();
foreach($results as $result) {
$matches = 0;
$resultStrs = explode(' ', $result);
foreach($resultStrs as $r) {
$strlen = strlen($r);
for($p = 0; $p < $strlen; $p++) {
if($reg[$p])
preg_match('/^['.$reg[$p].']/i',$r[$p],$match);
if($match==true) {
$matches++;
} else {
break 2;
}
}
}
$sort[$result] = $matches;
}
Это выводит массив с результатами по ключам, и сколько совпадений символов мы получили в сумме по значениям.
Причина, по которой я так выразилсячтобы избежать столкновений ключей, которые могут испортить мои данные, и что еще более важно, чтобы я мог быстро выполнить asort
и привести свои результаты в порядок.
Этот порядок обратный, и для ключей, так что послеПриведенный выше блок кода, я запускаю:
asort($sort);
$sort = array_reverse(array_keys($sort));
Это дает мне правильно проиндексированный массив результатов, отсортированный наиболее наименее релевантным.Теперь я могу просто выбросить это в поле автозаполнения.
Поскольку скорость - это весь смысл этого эксперимента, вот мои результаты - очевидно, они частично зависят от моего компьютера.
2 входных слова,40 результатов: ~ 5 мс 2 входных слова, (один символ, одно целое) 126 результатов: ~ 9 мс
Очевидно, что слишком много переменных поставлено на карту, чтобы эти результаты могли много значить для ВАС, но в качестве примера ядумаю, это довольно впечатляюще.
Если кто-то видит что-то не так с приведенным выше примером или может придумать лучший способ, чем это, я бы хотел услышать об этом.Единственное, о чем я могу думать, может быть, сейчас это вызывает проблемы, если бы я искал термин lean bimas
, я бы получил тот же результат, что и lima beans
, потому что шаблон не является условным на основании предыдущих совпадений.,Поскольку результаты, которые я ищу, и ожидаемые строки ввода не должны приводить к такому случаю, я решил оставить все как есть, чтобы избежать дополнительных затрат на этот быстрый маленький скрипт.Однако, если я в итоге почувствую, что мои результаты искажаются этим, я вернусь сюда и напишу о том, как я отсортировал эту часть.