Pregunta

Estoy tratando de poner en práctica un comparador personalizado en dos listas de cadenas y utilizar el método de LINQ .Except () para obtener los que no son uno a uno de las listas. La razón por la que estoy haciendo un comparador personalizado es porque tengo que hacer un "fuzzy" comparar, es decir, cadena de uno en uno lista podría ser embebido dentro de una cadena en la otra lista.

He hecho el siguiente comparador

public class ItemFuzzyMatchComparer : IEqualityComparer<string>
{
    bool IEqualityComparer<string>.Equals(string x, string y)
    {
        return (x.Contains(y) || y.Contains(x));
    }

    int IEqualityComparer<string>.GetHashCode(string obj)
    {
        if (Object.ReferenceEquals(obj, null))
            return 0;
        return obj.GetHashCode();
    }
}

Cuando elimino errores, el único punto de interrupción que éxitos está en el método GetHashCode (). Los Iguales () nunca llega tocaron. Algunas ideas?

¿Fue útil?

Solución

Si todos los códigos hash devueltos son diferentes, nunca se tiene que comparar la igualdad.

Básicamente, el problema es que sus conceptos de hash y la igualdad son muy diferentes. No estoy del todo seguro de cómo le gustaría corregir esto, pero hasta que haya hecho lo que sin duda no va a funcionar.

Debe asegurarse de que si Equals(a, b) devuelve verdadero, entonces GetHashCode(a) == GetHashCode(b). (Lo contrario no tiene por qué ser verdad -. Colisiones hash son aceptables, aunque obviamente usted quiere tener el menor número posible de ellos)

Otros consejos

Como Jon señaló, es necesario asegurarse de que el hash de código de dos cadenas que son iguales (de acuerdo con la regla de comparación). Esto es desgraciadamente bastante difícil.

Para demostrar el problema, vuelve Equals(str, "") cierto para todas las cadenas str, que esencialmente significa que todas las cadenas son iguales a una cadena vacía y, como resultado, todas las cadenas deben tener el mismo hash-código como una cadena vacía. Por lo tanto, la única manera de implementar correctamente IEqualityComparer es volver siempre el mismo hash-código:

public class ItemFuzzyMatchComparer : IEqualityComparer<string>  { 
  bool IEqualityComparer<string>.Equals(string x, string y)  { 
    return (x.Contains(y) || y.Contains(x)); 
  }  
  int IEqualityComparer<string>.GetHashCode(string obj)  { 
    if (Object.ReferenceEquals(obj, null)) return 0; 
    return 1; 
  } 
}

A continuación, se puede utilizar el método de Except y se comportará correctamente. El único problema es que usted (probablemente) obtener una aplicación bastante ineficiente, por lo que si usted necesita un mejor rendimiento, puede que tenga que poner en práctica su propia Except. Sin embargo, no estoy muy seguro de cómo ineficiente será la aplicación de LINQ y no estoy seguro de si es realmente posible tener cualquier implementación eficiente para su regla de comparación.

Tal vez este problema podría resolverse sin la implementación de la interfaz IEqualityComparer. Jon y Thomas tienen buenos puntos sobre la implementación de la interfaz, y no parece la igualdad para definir su problema. Desde su descripción, creo que se podría hacer esto sin usar la extensión Excepto durante la comparación. En su lugar, obtener los resultados más importantes primero, y luego hacer la excepción. A ver si esto hace el trabajo para usted:

 List<String> listOne = new List<string>(){"hard", "fun", "code", "rocks"};
 List<String> listTwo = new List<string>(){"fund", "ode", "ard"};

 var fuzzyMatchList = from str in listOne
                      from sr2 in listTwo
                      where str.Contains(sr2) || sr2.Contains(str)
                      select str;
 var exceptList = listOne.Except(fuzzyMatchList);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top