2010-10-13 26 views
6

Tengo un ObservableCollection, que tiene un objeto Person. Tengo una función de búsqueda en mi aplicación y me gustaría mostrar los resultados más relevantes en la parte superior. ¿Cuál sería la forma más eficiente de hacer esto? Mi método de búsqueda actual exige simplemente el método contains:Resultado de búsqueda de Linq por coincidencia más cercana

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

Esto funciona bien, pero los resultados se ordenan en el mismo orden en que aparecen en userList. Si busco Pete, primero debería mostrar Pete, luego Peter luego Peter Smith etc. No tiene que ser demasiado complicado ya que solo tratará con un par de miles de resultados (máx.). Mi enfoque ingenuo fue primero hacer s.Name == query, mostrar ese elemento (si lo hubiera), luego realizar el s.Name.Contains(query), eliminar el elemento coincidente y anexarlo al resultado coincidente anterior. Sin embargo, esto parece un poco por todas partes, ¿existe una mejor manera? gracias (ps - solo se usará el nombre en la búsqueda, y no puedo usar métodos SQL)

Respuesta

10

Puede hacer una única rutina que proporcione un nombre y una cadena de consulta, y devuelve un valor entero.

Una vez que usted tiene que, simplemente volver a través de pedidos por:

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

    return 1; 
} 

Luego hacer:

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

Lo bueno de este enfoque es que, más tarde, se podía extender la rutina para proporcionar más detalles, lo que le permite ordenar por la "buena" coincidencia que reciba. Por ejemplo, "Pete" -> "Peter" es probablemente una mejor coincidencia que "Pete" -> "Peter Smith", por lo que podría hacer que su lógica devuelva un valor diferente para las diferentes opciones ...

Si necesita eliminar coincidencias "no Pete", también puede excluir con una cláusula Where.

+0

Gracias, acabo de probar esto y parece funcionar perfectamente. Agradable y simple :) – Brap

7

Lo que necesita es algún tipo de función de puntuación por similitud. A continuación, sólo puede hacer:

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

Ahora bien, no está claro de su ejemplo exactamente (Eso es suponiendo una función de puntuación que da un valor entre 0-100, donde 100 es una combinación perfecta.) cuál debería ser la función de puntuación - eso es para que funcionen :)

+0

Gracias por la ayuda. Iba a buscar un método de distancia de Hamming, pero podría ser un poco excesivo e ineficiente para este problema. – Brap

0
var results = (from s in userList 
       where s.Name.Contains(query) 
       orderBy s.Length 
       select s).ToList(); 
Cuestiones relacionadas