2010-10-13 21 views
6

Ich habe eine ObservableCollection, die ein Person Objekt enthält. Ich habe eine Suchfunktion in meiner Anwendung und möchte die relevantesten Ergebnisse ganz oben anzeigen. Was wäre der effizienteste Weg, dies zu tun? Meine aktuelle Suchmethode ruft einfach die contains Methode:Linq Suchergebnis nach dem nächsten Treffer

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

Dies funktioniert gut, aber die Ergebnisse sind in der gleichen Reihenfolge, wie sie innerhalb userList erscheinen bestellt. Wenn ich nach Pete suche, dann sollte es zuerst Pete, dann Peter, dann Peter Smith etc. anzeigen. Es muss nicht zu kompliziert sein, da es nur mit ein paar tausend (max) Ergebnissen beschäftigt sein wird. Meine naive Herangehensweise war, zuerst s.Name == query zu machen, dieses Element anzuzeigen (falls vorhanden), dann das s.Name.Contains(query) auszuführen, das übereinstimmende Element zu entfernen und es an das vorherige übereinstimmende Ergebnis anzufügen. Dies scheint jedoch ein wenig überall und so gibt es einen besseren Weg? Danke (ps - nur der Name wird bei der Suche verwendet, und ich kann keine SQL-Methoden verwenden)

Antwort

10

Sie können eine einzelne Routine erstellen, die einen Namen und eine Abfrage-Zeichenfolge bereitstellt und einen ganzzahligen Wert zurückgibt.

Sobald Sie, dass nur über Auftrag Rückkehr nach:

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

    return 1; 
} 

Dann tun:

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

Das Schöne an diesem Ansatz ist, dass später Sie die Routine erweitern könnte zu schaffen Weitere Details, mit denen Sie nach dem "guten" Ergebnis eines Spiels sortieren können. Zum Beispiel, "Pete" -> "Peter" ist wahrscheinlich eine bessere Übereinstimmung als "Pete" -> "Peter Smith", so könnte Sie Ihre Logik einen anderen Wert für die verschiedenen Optionen zurückgeben ...

Wenn Sie Um "Nicht-Pete" -Matches zu entfernen, können Sie auch mit einer Where-Klausel ausschließen.

+0

Danke, ich habe es gerade getestet und es scheint perfekt zu funktionieren. Schön und einfach :) – Brap

7

Was Sie brauchen, ist eine Art von Scoring-Funktion für Ähnlichkeit. Dann können Sie einfach tun:

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

Jetzt ist es nicht klar, aus Ihrem Beispiel genau (das ist eine Bewertungsfunktion angenommen, die einen Wert zwischen 0-100 gibt, wobei 100 eine perfekte Übereinstimmung vorhanden ist.) Was die Scoring-Funktion sein sollte - das ist für Sie zu trainieren :)

+0

Danke für die Hilfe. Ich würde mich für eine Hamming-Distanz-Methode entscheiden, aber es könnte für dieses Problem etwas übertrieben und ineffizient sein. – Brap

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