Pour le bloc de code suivant:
For I = 0 To listOfStrings.Count - 1
If myString.Contains(lstOfStrings.Item(I)) Then
Return True
End If
Next
Return False
La sortie est:
Cas 1:
myString: C:\Files\myfile.doc
listOfString: C:\Files\, C:\Files2\
Result: True
Cas 2:
myString: C:\Files3\myfile.doc
listOfString: C:\Files\, C:\Files2\
Result: False
La liste (listOfStrings) peut contenir plusieurs éléments (minimum 20) et doit être vérifiée par rapport à des milliers de chaînes (comme ma chaîne).
Existe-t-il un meilleur moyen (plus efficace) d'écrire ce code?
Avec LINQ et en utilisant C # (je ne connais pas beaucoup VB de nos jours):
bool b = listOfStrings.Any(s=>myString.Contains(s));
ou (plus court et plus efficace, mais peut-être moins clair):
bool b = listOfStrings.Any(myString.Contains);
Si vous testiez l'égalité, il serait intéressant de regarder HashSet
etc.
update: si vous voulez vraiment dire "StartsWith", vous pouvez trier la liste et la placer dans un tableau; Ensuite, utilisez Array.BinarySearch
pour trouver chaque élément. Vérifiez par recherche si la correspondance est complète ou partielle.
lorsque vous construisez vos chaînes, il devrait être comme ça
bool inact = new string[] { "SUSPENDARE", "DIZOLVARE" }.Any(s=>stare.Contains(s));
Il y avait un certain nombre de suggestions d'une question similaire précédente " Le meilleur moyen de tester la chaîne existante par rapport à une longue liste de comparables ".
Regex pourrait suffire à vos besoins. L'expression serait une concaténation de toutes les sous-chaînes candidates, avec un opérateur OR "|
" entre elles. Bien sûr, vous devrez faire attention aux caractères non échappés lors de la construction de l'expression, ou à un échec de la compilation en raison de contraintes de complexité ou de taille.
Une autre façon de procéder serait de construire une structure de données trie pour représenter toutes les sous-chaînes candidates (cela pourrait en quelque sorte dupliquer ce que fait le matre regex). Au fur et à mesure que vous parcourez chaque caractère de la chaîne de test, vous devez créer un nouveau pointeur sur la racine du test et faire avancer les pointeurs existants sur l'enfant approprié (le cas échéant). Vous obtenez une correspondance lorsque n'importe quel pointeur atteint une feuille.
J'aimais la réponse de Marc, mais j'avais besoin de la correspondance de contenu pour être efficace.
C'était la solution:
bool b = listOfStrings.Any(s => myString.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0))
En fonction de vos habitudes, une amélioration consisterait à utiliser StartsWith au lieu de Contains. StartsWith doit seulement parcourir chaque chaîne jusqu'à ce qu'il trouve la première incompatibilité au lieu de devoir redémarrer la recherche à chaque position du caractère lorsqu'il en trouve une.
En outre, en fonction de vos modèles, il semble que vous puissiez extraire la première partie du chemin de myString, puis inverser la comparaison - en recherchant le chemin de départ de myString dans la liste des chaînes plutôt que l'inverse.
string[] pathComponents = myString.Split( Path.DirectorySeparatorChar );
string startPath = pathComponents[0] + Path.DirectorySeparatorChar;
return listOfStrings.Contains( startPath );
EDIT: Cela serait encore plus rapide en utilisant l’idée HashSet que @Marc Gravell mentionne puisque vous pouvez changer Contains
en ContainsKey
et la recherche serait O(1) au lieu de O (N). Vous devez vous assurer que les chemins correspondent exactement. Notez qu'il ne s'agit pas d'une solution générale, contrairement à celle de @Marc Gravell, mais qu'elle est adaptée à vos exemples.
Désolé pour l'exemple C #. Je n'ai pas eu assez de café pour traduire en VB.
Avez-vous testé la vitesse?
i.e. Avez-vous créé un échantillon de données et l’avez-vous profilé? Ce n'est peut-être pas aussi grave que vous le pensez.
Cela pourrait également être quelque chose que vous pourriez engendrer dans un fil séparé et donner l'illusion de vitesse!
Je ne sais pas si c'est plus efficace, mais vous pourriez penser à utiliser à Lambda Expressions .
L'inconvénient de la méthode Contains
est qu'elle ne permet pas de spécifier le type de comparaison, ce qui est souvent important lors de la comparaison de chaînes. Il est toujours sensible à la culture et à la casse. Donc, je pense que la réponse de WhoIsRich est précieuse, je veux juste montrer une alternative plus simple:
listOfStrings.Any(s => s.Equals(myString, StringComparison.OrdinalIgnoreCase))
myList.Any(myString.Contains);
Vieille question. Mais puisque VB.NET
était l'exigence d'origine. En utilisant les mêmes valeurs que la réponse acceptée:
listOfStrings.Any(Function(s) myString.Contains(s))
Si la vitesse est critique, vous pouvez rechercher l'algorithme Aho-Corasick pour des ensembles de modèles.
C'est un trie avec des liens d'échec, c'est-à-dire que la complexité est O (n + m + k), où n est la longueur du texte d'entrée, m la longueur cumulée des motifs et k le nombre de correspondances. Il vous suffit de modifier l’algorithme pour qu’il se termine une fois la première correspondance trouvée.