Für den folgenden Codeblock:
For I = 0 To listOfStrings.Count - 1
If myString.Contains(lstOfStrings.Item(I)) Then
Return True
End If
Next
Return False
Die Ausgabe ist:
Fall 1:
myString: C:\Files\myfile.doc
listOfString: C:\Files\, C:\Files2\
Result: True
Fall 2:
myString: C:\Files3\myfile.doc
listOfString: C:\Files\, C:\Files2\
Result: False
Die Liste (listOfStrings) kann mehrere Elemente enthalten (mindestens 20) und muss mit Tausenden von Zeichenfolgen (wie myString) verglichen werden.
Gibt es eine bessere (effizientere) Möglichkeit, diesen Code zu schreiben?
Mit LINQ und der Verwendung von C # (ich kenne VB heutzutage nicht viel):
bool b = listOfStrings.Any(s=>myString.Contains(s));
oder (kürzer und effizienter, aber wohl weniger klar):
bool b = listOfStrings.Any(myString.Contains);
Wenn Sie die Gleichheit testen, lohnt sich ein Blick auf HashSet
etc. Dies hilft jedoch nicht bei partiellen Übereinstimmungen, wenn Sie sie nicht in Fragmente aufteilen und eine Reihenfolge der Komplexität hinzufügen.
update: Wenn Sie wirklich "StartsWith" meinen, können Sie die Liste sortieren und in ein Array einfügen. Verwenden Sie dann Array.BinarySearch
, um jedes Element zu finden. Überprüfen Sie anhand der Suche, ob es sich um eine vollständige oder teilweise Übereinstimmung handelt.
wenn Sie Ihre Strings konstruieren, sollte es so sein
bool inact = new string[] { "SUSPENDARE", "DIZOLVARE" }.Any(s=>stare.Contains(s));
Es gab eine Reihe von Vorschlägen aus einer früheren ähnlichen Frage " Beste Methode, um den vorhandenen String gegen eine große Liste von Vergleichbaren zu testen ".
Regex könnte für Ihre Anforderung ausreichend sein. Der Ausdruck wäre eine Verkettung aller in Frage kommenden Teilzeichenfolgen mit einem OR "|
" -Operator zwischen ihnen. Natürlich müssen Sie beim Erstellen des Ausdrucks auf nicht maskierte Zeichen achten oder auf einen Fehler bei der Kompilierung aufgrund von Komplexitäts- oder Größenbeschränkungen achten.
Eine andere Möglichkeit, dies zu tun, wäre die Erstellung einer trie-Datenstruktur , um alle Kandidaten-Teilzeichenfolgen darzustellen (dies kann etwas die Wirkung des Regex-Matchers beeinträchtigen). Beim Durchlaufen der einzelnen Zeichen in der Testzeichenfolge erstellen Sie einen neuen Zeiger auf das Stammverzeichnis der Trie und verschieben vorhandene Zeiger auf das entsprechende untergeordnete Element (sofern vorhanden). Sie erhalten eine Übereinstimmung, wenn ein Zeiger ein Blatt erreicht.
Ich mochte Marc's Antwort, brauchte aber die Entsprechung Enthält CaSe InSenSiTiVe.
Dies war die Lösung:
bool b = listOfStrings.Any(s => myString.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0))
Basierend auf Ihren Mustern wäre eine Verbesserung die Verwendung von StartsWith anstelle von Enthält. StartsWith muss nur durch jede Zeichenfolge iterieren, bis es die erste Nichtübereinstimmung findet, anstatt die Suche an jeder Zeichenposition erneut starten zu müssen, wenn eine gefunden wird.
Auf der Grundlage Ihrer Muster scheint es auch so zu sein, dass Sie möglicherweise den ersten Teil des Pfads für myString extrahieren und den Vergleich rückgängig machen können. Dabei wird nach dem Startpfad von myString in der Liste der Zeichenfolgen gesucht und nicht umgekehrt.
string[] pathComponents = myString.Split( Path.DirectorySeparatorChar );
string startPath = pathComponents[0] + Path.DirectorySeparatorChar;
return listOfStrings.Contains( startPath );
EDIT: Dies wäre mit der HashSet-Idee von @Marc Gravell noch schneller, da Sie Contains
in ContainsKey
ändern könnten und die Suche O(1) anstelle von O (N) wäre. Sie müssen sicherstellen, dass die Pfade genau übereinstimmen. Beachten Sie, dass dies keine generelle Lösung ist, wie @Marc Gravell, sondern auf Ihre Beispiele zugeschnitten ist.
Sorry für das C # -Beispiel. Ich habe nicht genug Kaffee gehabt, um ihn in VB zu übersetzen.
Hast du die Geschwindigkeit getestet?
haben Sie einen Beispieldatensatz erstellt und ein Profil erstellt? Es kann nicht so schlimm sein, wie Sie denken.
Dies könnte auch etwas sein, das Sie in einen separaten Thread verwandeln und die Illusion von Geschwindigkeit vermitteln können!
Ich bin nicht sicher, ob es effizienter ist, aber Sie könnten an Lambda Expressions denken.
Der Nachteil der Contains
-Methode besteht darin, dass es nicht möglich ist, einen Vergleichstyp anzugeben, der beim Vergleichen von Zeichenfolgen häufig wichtig ist. Es ist immer kulturempfindlich und Groß-/Kleinschreibung. Ich denke, die Antwort von WhoIsRich ist wertvoll, ich möchte nur eine einfachere Alternative zeigen:
listOfStrings.Any(s => s.Equals(myString, StringComparison.OrdinalIgnoreCase))
myList.Any(myString.Contains);
Alte Frage. Aber da war VB.NET
die ursprüngliche Anforderung. Verwenden Sie die gleichen Werte der akzeptierten Antwort:
listOfStrings.Any(Function(s) myString.Contains(s))
Wenn die Geschwindigkeit von entscheidender Bedeutung ist, sollten Sie nach dem Aho-Corasick-Algorithmus nach Mustersätzen suchen.
Es ist ein trie mit Fehlerlinks, dh die Komplexität ist O (n + m + k), wobei n die Länge des Eingabetextes ist, m die kumulative Länge der Muster und k die Anzahl der Übereinstimmungen ist. Sie müssen nur den Algorithmus so ändern, dass er beendet wird, nachdem die erste Übereinstimmung gefunden wurde.