Controlla se una stringa contiene un elemento da una lista (di stringhe)

Per il seguente blocco di codice:

For I = 0 To listOfStrings.Count - 1 If myString.Contains(lstOfStrings.Item(I)) Then Return True End If Next Return False 

L’output è:

Caso 1:

 myString: C:\Files\myfile.doc listOfString: C:\Files\, C:\Files2\ Result: True 

Caso 2:

 myString: C:\Files3\myfile.doc listOfString: C:\Files\, C:\Files2\ Result: False 

L’elenco (listOfStrings) può contenere diversi elementi (minimo 20) e deve essere verificato su migliaia di stringhe (come myString).

C’è un modo migliore (più efficiente) per scrivere questo codice?

Con LINQ e usando C # (non conosco VB molto in questi giorni):

 bool b = listOfStrings.Any(s=>myString.Contains(s)); 

o (più breve e più efficiente, ma probabilmente meno chiaro):

 bool b = listOfStrings.Any(myString.Contains); 

Se si testasse l’uguaglianza, varrebbe la pena dare HashSet a HashSet , ecc, ma questo non è d’aiuto con le corrispondenze parziali a meno che non lo si divida in frammenti e si aggiunga un ordine di complessità.


aggiornamento: se si intende realmente “Inizia con”, è ansible ordinare l’elenco e inserirlo in un array; quindi usa Array.BinarySearch per trovare ogni elemento: controlla per ricerca per vedere se si tratta di una corrispondenza completa o parziale.

C’erano una serie di suggerimenti da una domanda simile precedente “Il modo migliore per verificare la presenza di una stringa esistente in un ampio elenco di comparabili “.

Regex potrebbe essere sufficiente per le tue esigenze. L’espressione sarebbe una concatenazione di tutte le sottostringhe candidate, con un operatore OR ” | ” tra di loro. Ovviamente, dovrai fare attenzione a caratteri senza escape quando costruisci l’espressione, o fallire nel compilarlo a causa di limiti di complessità o dimensioni.

Un altro modo per farlo sarebbe build una struttura dati trie per rappresentare tutte le sottostringhe candidate (questo potrebbe in qualche modo duplicare ciò che sta facendo il regex matcher). Mentre passi attraverso ogni carattere nella stringa di test, creerai un nuovo puntatore alla radice del trie e avanzi i puntatori esistenti al figlio appropriato (se ce ne sono). Si ottiene una corrispondenza quando qualsiasi puntatore raggiunge una foglia.

quando costruisci le tue corde dovrebbe essere così

 bool inact = new string[] { "SUSPENDARE", "DIZOLVARE" }.Any(s=>stare.Contains(s)); 

Mi è piaciuta la risposta di Marc, ma avevo bisogno che il contenuto di Contains fosse CaSe InSenSiTiVe.

Questa era la soluzione:

 bool b = listOfStrings.Any(s => myString.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0)) 

In base ai tuoi modelli, un miglioramento sarebbe passare all’utilizzo di StartsWith anziché di Contains. Inizia con Bisogna solo scorrere tutte le stringhe fino a quando non trova la prima discrepanza invece di dover riavviare la ricerca in ogni posizione del personaggio quando ne trova una.

Inoltre, in base ai tuoi pattern, sembra che tu possa essere in grado di estrarre la prima parte del percorso per myString, quindi invertire il confronto – cercando il percorso iniziale di myString nell’elenco di stringhe piuttosto che il contrario.

 string[] pathComponents = myString.Split( Path.DirectorySeparatorChar ); string startPath = pathComponents[0] + Path.DirectorySeparatorChar; return listOfStrings.Contains( startPath ); 

EDIT : Questo sarebbe ancora più veloce usando l’idea di HashSet @Marc Gravell menziona dato che potresti cambiare Contains a ContainsKey e la ricerca sarebbe O (1) invece di O (N). Dovresti assicurarti che i percorsi corrispondano esattamente. Nota che questa non è una soluzione generale come quella di @Marc Gravell, ma è adattata ai tuoi esempi.

Ci scusiamo per l’esempio C #. Non ho avuto abbastanza caffè da tradurre in VB.

Non sono sicuro che sia più efficiente, ma potresti pensare di utilizzare Lambda Expressions .

Hai provato la velocità?

cioè hai creato un campione di dati e lo hai profilato? Potrebbe non essere così male come pensi.

Questo potrebbe anche essere qualcosa che potresti generare in un thread separato e dare l’illusione della velocità!

Se la velocità è critica, potresti voler cercare l’ algoritmo Aho-Corasick per serie di modelli.

È un trie con link di errore, ovvero la complessità è O (n + m + k), dove n è la lunghezza del testo di input, m la lunghezza cumulativa dei pattern e k il numero di corrispondenze. Devi solo modificare l’algoritmo per terminare dopo aver trovato la prima corrispondenza.

 myList.Any(myString.Contains);