C # distinct sur IEnumerable < T > avec IEqualityComparer personnalisé
-
10-07-2019 - |
Question
Voici ce que j'essaie de faire. J'interroge un fichier XML à l'aide de LINQ to XML, ce qui me donne un IEnumerable < T
> objet, où T est mon " Village " classe, rempli avec les résultats de cette requête. Certains résultats sont dupliqués. Par conséquent, j'aimerais effectuer Distinct () sur l'objet IEnumerable, comme suit:
public IEnumerable<Village> GetAllAlliances()
{
try
{
IEnumerable<Village> alliances =
from alliance in xmlDoc.Elements("Village")
where alliance.Element("AllianceName").Value != String.Empty
orderby alliance.Element("AllianceName").Value
select new Village
{
AllianceName = alliance.Element("AllianceName").Value
};
// TODO: make it work...
return alliances.Distinct(new AllianceComparer());
}
catch (Exception ex)
{
throw new Exception("GetAllAlliances", ex);
}
}
Comme le comparateur par défaut ne fonctionnerait pas pour l'objet Village, j'ai mis en place un paramètre personnalisé, comme indiqué ici dans la classe AllianceComparer:
public class AllianceComparer : IEqualityComparer<Village>
{
#region IEqualityComparer<Village> Members
bool IEqualityComparer<Village>.Equals(Village x, Village y)
{
// Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y))
return true;
// Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.AllianceName == y.AllianceName;
}
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.GetHashCode();
}
#endregion
}
La méthode Distinct () ne fonctionne pas, car j’ai exactement le même nombre de résultats avec ou sans celle-ci. Une autre chose, et je ne sais pas si c'est généralement possible, mais je ne peux pas entrer dans AllianceComparer.Equals () pour voir quel pourrait en être le problème.
J'ai trouvé des exemples de cela sur Internet, mais je n'arrive pas à faire en sorte que mon implémentation fonctionne.
J'espère que quelqu'un ici pourra voir ce qui pourrait ne pas se passer ici! Merci d'avance!
La solution
Le problème vient de votre GetHashCode
. Vous devriez le modifier pour renvoyer le code de hachage de NomAlliance
à la place.
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.AllianceName.GetHashCode();
}
En réalité, si est égal à
renvoie true
, les objets doivent avoir le même code de hachage, ce qui n'est pas le cas pour différents objets Village
. avec le même nom d'alliance
. Distinct
fonctionnant en construisant une table de hachage en interne, vous obtiendrez des objets identiques qui ne seront pas du tout mis en correspondance en raison de codes de hachage différents.
De même, pour comparer deux fichiers, si le hachage de deux fichiers n'est pas identique, vous n'avez pas besoin de vérifier les fichiers eux-mêmes. Ils seront différents. Sinon, vous continuerez à vérifier s'ils sont vraiment identiques ou non. C’est exactement ce que la table de hachage utilisée par Distinct
se comporte.
Autres conseils
renvoyer des alliances.Sélectionner (v = > v.AllianceName) .Distinct ();
Cela renverrait un IEnumerable < chaîne >
au lieu de IEnumerable < Village >
.
Ou changez de ligne
return alliances.Distinct(new AllianceComparer());
à
return alliances.Select(v => v.AllianceName).Distinct();