Question

Je suis en train de mettre en place un comparateur personnalisé sur deux listes de chaînes et utiliser la méthode LINQ .Except () pour obtenir ceux qui ne sont pas une une des listes. La raison pour laquelle je fais un comparateur personnalisé est parce que je dois faire une « floue » comparer, à savoir une chaîne sur une liste pourrait être intégrée dans une chaîne sur l'autre liste.

J'ai fait le comparateur suivant

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();
    }
}

Quand je debug, le seul point d'arrêt qui frappe est la méthode GetHashCode (). Egaux () ne fait jamais touché. Toutes les idées?

Était-ce utile?

La solution

Si tous les codes de hachage retournés sont différents, il faut ne jamais comparer l'égalité.

Fondamentalement, le problème est que vos concepts de hachage et l'égalité sont très différents. Je ne suis pas tout à fait sûr comment vous corriger cela, mais jusqu'à ce que vous avez fait, il ne fonctionnera certainement pas.

Vous devez vous assurer que si Equals(a, b) retourne vrai, GetHashCode(a) == GetHashCode(b). (L'inverse ne doit pas être vrai -. Collisions de hachage sont acceptables, bien évidemment vous voulez avoir aussi peu d'entre eux que possible)

Autres conseils

Comme Jon a souligné, vous devez vous assurer que le code de hachage de deux chaînes qui sont égales (selon votre règle de comparaison). Ceci est unfortunatelly assez difficile.

Pour démontrer le problème, Equals(str, "") retourne vrai pour toutes les chaînes str, ce qui signifie essentiellement que toutes les chaînes sont égales à une chaîne vide et par conséquent, toutes les chaînes doivent avoir le même code-hachage comme une chaîne vide. Par conséquent, la seule façon de mettre en œuvre IEqualityComparer est correctement pour revenir toujours le même hachage code:

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; 
  } 
}

Ensuite, vous pouvez utiliser la méthode Except et il se comportera correctement. Le seul problème est que vous (probablement) obtenez une mise en œuvre assez inefficace, donc si vous avez besoin de meilleures performances, vous pouvez avoir à mettre en œuvre votre propre Except. Cependant, je ne sais pas exactement comment la mise en œuvre inefficace LINQ sera et je ne sais pas s'il est effectivement possible d'avoir une mise en œuvre efficace pour votre règle de comparaison.

Peut-être que ce problème pourrait être résolu sans la mise en œuvre de l'interface IEqualityComparer. Jon et Thomas ont de bons points sur la mise en œuvre de cette interface, et l'égalité ne semble pas définir votre problème. D'après votre description, je pense que vous pouvez le faire sans utiliser l'exception Allongement à la comparaison. Au lieu de cela, obtenir les matchs d'abord, puis faire l'exception. Voir si cela fait le travail pour vous:

 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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top