Zuerst würde ich ändern , wie ListControl
Ihre Datenquelle sieht, die Sie konvertieren Ergebnis IEnumerable<string>
zu List<string>
. Insbesondere wenn Sie nur wenige Zeichen eingegeben haben, kann dies ineffizient (und nicht erforderlich) sein. Erstellen Sie keine umfangreichen Kopien Ihrer Daten .
- Ich würde das
.Where()
Ergebnis in eine Sammlung einbinden , die nur das implementiert, was von IList
(Suche) benötigt wird. Auf diese Weise können Sie für jedes eingegebene Zeichen eine neue große Liste erstellen.
- Als Alternative würde ich LINQ vermeiden und etwas Spezifischeres (und Optimiertes) schreiben. Behalten Sie Ihre Liste im Speicher und erstellen Sie ein Array übereinstimmender Indizes. Verwenden Sie das Array erneut, damit Sie es nicht bei jeder Suche neu zuweisen müssen.
Der zweite Schritt besteht darin, nicht in der großen Liste zu suchen, wenn eine kleine ausreicht. Wenn der Benutzer "ab" eingibt und "c" hinzufügt, müssen Sie nicht in der großen Liste recherchieren. Die Suche in der gefilterten Liste ist ausreichend (und schneller). Suche jedes Mal verfeinern ist möglich. Führen Sie nicht jedes Mal eine vollständige Suche durch.
Der dritte Schritt kann schwieriger sein: Halten Sie die Daten so organisiert, dass sie schnell durchsucht werden können . Jetzt müssen Sie die Struktur ändern, in der Sie Ihre Daten speichern. Stellen Sie sich einen Baum wie diesen vor:
ABC
Bessere Decke hinzufügen
Über der Knochenkontur
Dies kann einfach mit einem Array implementiert werden (wenn Sie mit ANSI-Namen arbeiten, wäre sonst ein Wörterbuch besser). Erstellen Sie die Liste wie folgt (zur Veranschaulichung entspricht sie dem Anfang der Zeichenfolge):
var dictionary = new Dictionary<char, List<string>>();
foreach (var user in users)
{
char letter = user[0];
if (dictionary.Contains(letter))
dictionary[letter].Add(user);
else
{
var newList = new List<string>();
newList.Add(user);
dictionary.Add(letter, newList);
}
}
Die Suche wird dann mit dem ersten Zeichen durchgeführt:
char letter = textBox_search.Text[0];
if (dictionary.Contains(letter))
{
listBox_choices.DataSource =
new MyListWrapper(dictionary[letter].Where(x => x.Contains(textBox_search.Text)));
}
Bitte beachten Sie, dass ich MyListWrapper()
wie im ersten Schritt vorgeschlagen verwendet habe (aber ich habe den zweiten Vorschlag der Kürze halber weggelassen. Wenn Sie die richtige Größe für den Wörterbuchschlüssel wählen, können Sie jede Liste kurz und schnell halten, um - vielleicht - etwas anderes zu vermeiden). Beachten Sie außerdem, dass Sie möglicherweise versuchen, die ersten beiden Zeichen für Ihr Wörterbuch zu verwenden (mehr Listen und kürzere). Wenn Sie dies erweitern, haben Sie einen Baum (aber ich glaube nicht, dass Sie so viele Gegenstände haben).
Es gibt viele verschiedene Algorithmen für die Zeichenfolgensuche (mit verwandten Datenstrukturen), um nur einige zu nennen:
- Suche nach endlichen Zustandsautomaten : Bei diesem Ansatz vermeiden wir das Zurückverfolgen, indem wir einen deterministischen endlichen Automaten (DFA) konstruieren, der gespeicherte Suchzeichenfolgen erkennt. Diese sind teuer in der Konstruktion - sie werden normalerweise mit der Powerset-Konstruktion erstellt -, aber sehr schnell zu verwenden.
- Stubs : Knuth-Morris-Pratt berechnet einen DFA, der Eingaben mit der zu suchenden Zeichenfolge als Suffix erkennt. Boyer-Moore beginnt am Ende der Nadel mit der Suche, sodass bei jedem Schritt normalerweise eine ganze Nadellänge vorausgesprungen werden kann. Baeza-Yates verfolgt, ob die vorherigen j Zeichen ein Präfix der Suchzeichenfolge waren, und ist daher an die Suche nach Fuzzy-Zeichenfolgen anpassbar. Der Bitap-Algorithmus ist eine Anwendung des Baeza-Yates-Ansatzes.
- Indexmethoden : Schnellere Suchalgorithmen basieren auf der Vorverarbeitung des Textes. Nach dem Erstellen eines Teilzeichenfolgenindex, beispielsweise eines Suffixbaums oder eines Suffixarrays, können die Vorkommen eines Musters schnell gefunden werden.
- Andere Varianten : Einige Suchmethoden, beispielsweise die Trigrammsuche, sollen eher eine "Nähe" zwischen der Suchzeichenfolge und dem Text als eine "Übereinstimmung / Nichtübereinstimmung" finden. Diese werden manchmal als "Fuzzy" -Suchen bezeichnet.
Einige Worte zur parallelen Suche. Es ist möglich, aber es ist selten trivial, da der Overhead, um es parallel zu machen, leicht viel höher sein kann als die Suche selbst. Ich würde die Suche nicht parallel durchführen (Partitionierung und Synchronisation werden bald zu umfangreich und möglicherweise komplex), aber ich würde die Suche in einen separaten Thread verschieben . Wenn der Haupt-Thread nicht ausgelastet ist, spüren Ihre Benutzer während der Eingabe keine Verzögerung (sie bemerken nicht, ob die Liste nach 200 ms angezeigt wird, fühlen sich jedoch unwohl, wenn sie 50 ms nach der Eingabe warten müssen). . Natürlich muss die Suche selbst schnell genug sein. In diesem Fall verwenden Sie keine Threads, um die Suche zu beschleunigen, sondern um Ihre Benutzeroberfläche ansprechbar zu halten . Bitte beachten Sie, dass ein separater Thread Ihre Anfrage nicht stelltschneller , die Benutzeroberfläche bleibt nicht hängen, aber wenn Ihre Abfrage langsam war, ist sie in einem separaten Thread immer noch langsam (außerdem müssen Sie auch mehrere sequenzielle Anforderungen verarbeiten).
HashSet<T>
wird Ihnen hier nicht helfen, weil Sie den Teil der Zeichenfolge suchen .