2010-10-13 2 views
6

У меня есть ObservableCollection, в котором находится объект Person. У меня есть функция поиска в моем приложении и вы хотите отобразить наиболее релевантные результаты в верхней части. Какой был бы самый эффективный способ сделать это? Мой текущий метод поиска просто вызывает contains метода:Результаты поиска Linq по ближайшему совпадению

var results = (from s in userList 
       where s.Name.Contains(query) 
       select s).ToList(); 

Это прекрасно работает, но результаты упорядочены в том же порядке, как они появляются в userList. Если я ищу Pete, тогда он должен сначала отобразить Pete, затем Peter, затем Peter Smith и т. Д. Это не должно быть слишком сложно, так как оно будет иметь дело только с несколькими тысячами (максимальными) результатами. Мой наивный подход состоял в том, чтобы сначала сделать s.Name == query, отобразить этот элемент (если есть), затем выполнить команду s.Name.Contains(query), удалить соответствующий элемент и добавить его к предыдущему согласованному результату. Однако, это кажется немного повсюду, и есть ли лучший способ? спасибо (ps - только имя будет использоваться при поиске, и я не могу использовать SQL-методы)

ответ

10

Вы можете создать единую подпрограмму, которая предоставляет имя и строку запроса и возвращает целочисленное значение.

Как только вы что, просто вернуться через порядке:

int QueryOrder(string query, string name) 
{ 
    if (name == query) 
     return -1; 
    if (name.Contains(query)) 
     return 0; 

    return 1; 
} 

Затем сделать:

var results = userList.OrderBy(s => QueryOrder(query, s.Name)); 

Хорошая вещь об этом подходе является то, что позже, вы можете продлить процедуру, чтобы обеспечить более подробную информацию, позволяющую вам сортировать, как «хорошо» в матче, который вы получаете. Например, «Пит» -> «Питер», вероятно, лучше, чем «Пит» -> «Питер Смит», так что вы могли бы вернуть свою логику для разных опций другого значения ...

Если вы необходимо удалить совпадения «не-Пит», вы также можете исключить предложение Where.

+0

Спасибо, я просто испытал это и, похоже, работает отлично. Приятно и просто :) – Brap

7

Что вам нужно, это какая-то функция подсчета очков для подобия. Тогда вы можете просто сделать:

from s in userList 
let score = Score(s, query) 
where score > 80 
orderby score descending 
select s; 

Теперь это не ясно из вашего примера точно (Это допускающая функцию подсчета очков, которая дает значение между 0-100, где 100 представляет собой идеальный матч.) какая должна быть функция подсчета очков - это для вас, чтобы выработать :)

+0

Спасибо за помощь. Я собирался пойти на метод расстояния Хэмминга, но это может быть немного излишним и неэффективным для этой проблемы. – Brap

0
var results = (from s in userList 
       where s.Name.Contains(query) 
       orderBy s.Length 
       select s).ToList(); 
Смежные вопросы