2010-09-24 28 views
6

Tengo dos cadenas que contienen letras y números separados por espacios. ex "elza7ma wa2fa fel matab" y "2ana ba7eb el za7ma 2awy 2awy"C# compare dos cadenas para palabras coincidentes

¿Cuál es la forma más rápida de comparar estas dos cadenas para saber si tienen una palabra en común o no?

Intenté dividir uno de ellos utilizando string.split y uso string.compare en toda la matriz de palabras. pero esto es muy lento ya que voy a comparar muchas cadenas.

+0

parece que indexOf funcionará más rápido que regex, sin embargo, no sé si es más rápido que string.compare :). Puedes probar – Danil

+1

¿De verdad quieres * el más rápido *? Podría trabajar literalmente * años * en ese problema. Sospecho que quieres * lo suficientemente rápido *, en cuyo caso, no has dado suficiente información para resolver el problema. * ¿Cuál es su hardware, cuál es su presupuesto de tiempo y cuál es un problema de tamaño típico? * –

+3

Además, ¿qué significa "muchas cadenas"? Sus comentarios a continuación indican que "mucho" es cientos. Consideraría que cientos son * un número increíblemente pequeño de cadenas *. Es eso exacto? Consideraría "mucho" millones o miles de millones de cadenas, como en, Bing indexa muchas cadenas. Sin tener una buena idea del tamaño del problema, es difícil darle una buena respuesta. –

Respuesta

14

Una solución LINQ

"elza7ma wa2fa fel matab".Split() 
         .Intersect("2ana ba7eb el za7ma 2awy 2awy".Split()) 
         .Any(); 

// as a string extension method 
public static class StringExtensions 
{ 
    public static bool OneWordMatches(this string theString, string otherString) 
    { 
     return theString.Split().Intersect(otherString.Split()).Any(); 
    } 
} 

// returns true 
"elza7ma wa2fa fel matab 2ana".OneWordMatches("2ana ba7eb el za7ma 2awy 2awy"); 
+0

Sin sobrecarga de 'Split' toma un solo' char'. Probablemente sea mejor especificar también 'RemoveEmptyEntries' – JaredPar

+0

Puede usar' Split() 'sin ningún parámetro. En este caso, usará espacios, pestañas y nuevas líneas como separador. – Oliver

+0

¿Es esto realmente más rápido o Intersecta() también recorre ambas matrices? – Sjoerd

5

creo que la forma más fácil es romper las cadenas en las palabras y el uso de una estructura de conjunto como HashSet<string> para comprobar si hay duplicados. Por ejemplo

public bool HasMatchingWord(string left, string right) { 
    var hashSet = new HashSet<string>(
    left.Split(" ", StringSplitOptions.RemoveEmptyEntries)); 
    return right 
    .Split(" ", StringSplitOptions.RemoveEmptyEntries) 
    .Any(x => hashSet.Contains(x)); 
} 
+1

Podría agregar una verificación de igualdad también para manejar colisiones (si las hay). –

+0

¿Alguien está seguro si este es el mejor método de rendimiento? – Marwan

1

Puede dividir las dos cadenas por palabra y construir dos hashtables/diccionarios. A continuación, vaya a ambos y agregue las teclas incrementando un int en un tercer diccionario (Dictionary<string, int>). Si alguna tecla en el tercer diccionario tiene un conteo de más de uno, esa palabra está en ambas cadenas originales.

Creo que cualquier algoritmo para resolver este problema sería 'lento', especialmente para grandes cadenas de entrada/muchas palabras.

+0

Agregar todas las palabras al mismo HashSet y comprobar el valor de retorno de Agregar() es más simple. – Sjoerd

+0

Releí la pregunta original, sí, sería mucho más simple. Solo está preguntando si hay palabras que estén representadas en ambas cadenas, no cuáles y no cuántas ocurrencias. – mbanzon

0

Probablemente tomaré el golpe de rendimiento inicial y dividiré la cadena y luego ordenaré alfabéticamente y por longitud de palabra. Si solo tiene que averiguar si una palabra concuerda, rompa en cuanto la encuentre. Una vez que tiene las matrices de cadenas divididas ordenadas alfabéticamente y por longitud, eso limita el número de comparaciones que tendría que hacer.

0
  • La manera más fácil sería comparar todas las palabras con cualquier otra palabra. Esta es una solución fácil, pero lenta.
  • Otra forma es ordenar ambas listas, y luego comparar las dos entradas superiores. Como mergesort, pero con el objetivo de encontrar palabras iguales.
  • Otra forma es compilar la lista de palabras en un árbol y hacer coincidir las palabras con ese árbol. Una expresión regular puede hacer esto, o puede hacerlo usted mismo. En su ejemplo, la primera letra debe ser 2, b, e o z. De esta forma, cada palabra solo se inspecciona una vez y se inspecciona el menor número de caracteres.
Cuestiones relacionadas