164 votes

Comment HashSet compare-t-il les éléments pour l'égalité?

J'ai une classe c'est - IComparable:

public class a : IComparable
{
    public int Id { get; set; }
    public string Name { get; set; }

    public a(int id)
    {
        this.Id = id;
    }

    public int CompareTo(object obj)
    {
        return this.Id.CompareTo(((a)obj).Srl);
    }
}

Quand j'ajoute une liste d'objet de cette classe à un ensemble de hachage:

a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(a1);

Tout est beau et ha.count est 2, mais:

a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(new a(1));

Maintenant, ha.count est 3.

  1. Pourquoi ne peut - HashSet respecter as' CompareTo méthode.
  2. Est - HashSet le meilleur moyen d'avoir une liste d'objets uniques?

187voto

Jon Skeet Points 692016

Il utilise un IEqualityComparer<T> (EqualityComparer<T>.Default , sauf si vous spécifiez un autre sur la construction).

Lorsque vous ajoutez un élément à l'ensemble, il va trouver le code de hachage à l'aide de IEqualityComparer<T>.GetHashCode, et de stocker le code de hachage et l'élément (après avoir vérifié si l'élément est déjà dans le jeu, bien sûr).

Pour rechercher un élément, il va d'abord utiliser l' IEqualityComparer<T>.GetHashCode pour trouver le code de hachage, puis pour tous les éléments avec le même code de hachage, il utilisera IEqualityComparer<T>.Equals à comparer à une véritable égalité.

Notez la façon dont aucun n'est dans les termes d'une ordonnée de la comparaison, ce qui est logique, car il ya certainement des situations où vous pouvez facilement spécifier l'égalité, mais pas un total de la commande. C'est tout de même que l' Dictionary<TKey, TValue>, essentiellement.

Si vous voulez un jeu qui utilise la commande au lieu de juste égalité des comparaisons, vous devez utiliser SortedSet<T> de .NET 4 - qui vous permet de spécifier un IComparer<T> au lieu d'un IEqualityComparer<T>. Cela permettra d'utiliser IComparer<T>.Compare - qui sera délégué IComparable<T>.CompareTo ou IComparable.CompareTo si vous utilisez Comparer<T>.Default.

98voto

tyriker Points 528

Voici des précisions sur une partie de la réponse qui a été occultée: Le type d'objet de votre HashSet<T> n'a pas à mettre en oeuvre IEqualityComparer<T> , mais plutôt juste a remplacer Object.GetHashCode() et Object.Equals(Object obj).

Au lieu de cela:

public class a : IEqualityComparer<a>
{
  public int GetHashCode(a obj) { /* Implementation */ }
  public bool Equals(a obj1, a obj2) { /* Implementation */ }
}

Pour ce faire:

public class a
{
  public override int GetHashCode() { /* Implementation */ }
  public override bool Equals(a obj) { /* Implementation */ }
}

C'est subtil, mais cela s'est déclenché moi pour la meilleure partie de la journée à essayer d'obtenir HashSet à la fonction de la façon dont il est conçu. Et comme d'autres l'ont dit, HashSet<a> finiront par appeler a.GetHashCode() et a.Equals(obj) que nécessaire lorsque l'on travaille avec l'ensemble.

16voto

CodesInChaos Points 60274

HashSet utilise Equals et GetHashCode() .

CompareTo est destiné aux ensembles commandés.

Si vous voulez des objets uniques, mais vous ne vous souciez pas de leur ordre d'itération, HashSet<T> est généralement le meilleur choix.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X