Comprobar si una cadena contiene un elemento de una lista (de cadenas)


Para el siguiente bloque de código:

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

La salida es:

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

La lista (listOfStrings) puede contener varios elementos (mínimo 20) y debe ser contrastada con miles de cadenas (como myString).

¿Hay una manera mejor (más eficiente) de escribir este código?

Author: Dukeling, 2009-02-01

9 answers

Con LINQ, y usando C# (no se mucho VB en estos días):

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

O (más corto y más eficiente, pero posiblemente menos claro):

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

Si estuviera probando la igualdad, valdría la pena mirar HashSet, etc., pero esto no ayudará con las coincidencias parciales a menos que lo divida en fragmentos y agregue un orden de complejidad.


Actualización: si realmente quiere decir "startsWith", entonces puede ordenar la lista y colocarla en una matriz; luego use Array.BinarySearch para encontrar cada elemento-check by busque para ver si es una coincidencia total o parcial.

 265
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-01 20:35:32

Hubo una serie de sugerencias de una pregunta similar anterior " La mejor manera de probar la cadena existente contra una gran lista de comparables".

Regex podría ser suficiente para su requerimiento. La expresión sería una concatenación de todas las subcadenas candidatas, con un operador OR "|" entre ellas. Por supuesto, tendrá que tener cuidado con los caracteres no grabados al construir la expresión, o si no se compila debido a la complejidad o el tamaño limitacion.

Otra forma de hacer esto sería construir una estructura de datos trie para representar todas las subcadenas candidatas (esto puede duplicar algo lo que está haciendo el comparador de expresiones regulares). A medida que avanza a través de cada carácter en la cadena de prueba, crearía un nuevo puntero a la raíz del trie y avanzaría los punteros existentes al hijo apropiado (si lo hubiera). Se obtiene una coincidencia cuando cualquier puntero llega a una hoja.

 5
Author: Zach Scrivena,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:05

Cuando construyes tus cadenas debería ser así

bool inact = new string[] { "SUSPENDARE", "DIZOLVARE" }.Any(s=>stare.Contains(s));
 3
Author: Simi2525,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-19 09:19:35

Me gustó la respuesta de Marc, pero necesitaba que las coincidencias de los Contenidos fueran insensibles a Mayúsculas y minúsculas.

Esta fue la solución:

bool b = listOfStrings.Any(s => myString.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0))
 3
Author: WhoIsRich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-05 19:41:36

Basado en sus patrones, una mejora sería cambiar a usar startsWith en lugar de Contains. startsWith solo necesita iterar a través de cada cadena hasta que encuentre el primer desajuste en lugar de tener que reiniciar la búsqueda en cada posición de carácter cuando encuentre uno.

Además, en función de sus patrones, parece que puede extraer la primera parte de la ruta para myString, luego revertir la comparación looking buscando la ruta de inicio de myString en la lista de cadenas en lugar de al revés.

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

return listOfStrings.Contains( startPath );

EDITAR : Esto sería aún más rápido usando el HashSet idea @Marc Gravell menciones ya que podrías cambiar Contains a ContainsKey y la búsqueda sería O(1) en lugar de O(N). Usted tendría que asegurarse de que los caminos coinciden exactamente. Ten en cuenta que esta no es una solución general como la de @Marc Gravell, sino que está adaptada a tus ejemplos.

Lo siento por el ejemplo de C#. No he tomado suficiente café para traducir a VB.

 2
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-01 15:17:23

No estoy seguro de si es más eficiente, pero podría pensar en usar Expresiones at Lambda.

 1
Author: Mark Carpenter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-01 14:44:21

Has probado la velocidad?

Es decir, ¿ha creado un conjunto de datos de muestra y lo ha perfilado? Puede que no sea tan malo como crees.

Esto también podría ser algo que podría aparecer en un hilo separado y dar la ilusión de velocidad!

 1
Author: Fortyrunner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-01 20:50:28

Si la velocidad es crítica, es posible que desee buscar el algoritmo Aho-Corasick para conjuntos de patrones.

Es un trie con enlaces de falla, es decir, la complejidad es O(n+m+k), donde n es la longitud del texto de entrada, m la longitud acumulada de los patrones y k el número de coincidencias. Solo tienes que modificar el algoritmo para terminar después de que se encuentre la primera coincidencia.

 0
Author: Torsten Marek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-16 16:22:30
myList.Any(myString.Contains);
 0
Author: WIRN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-25 08:15:38