9
votes

Utilisation de gethashcode pour tester l'égalité dans les égaux de remplacement

est-il correct d'appeler gethashcode comme une méthode pour tester l'égalité de l'intérieur de l'intérieur du remplacement des égaux?

Par exemple, est-ce que ce code est acceptable? xxx


5 commentaires

En tant que développeur, vous devez bien comprendre ce que les hachages sont utilisés et comment ils se rapportent aux tables de hachage (comme implémentées par le dictionnaire et le hashset, entre autres). L'article Wikipedia pour Hashtable est un bon départ: en.wikipedia.org/wiki/hash_table


@Spender - c'est exactement ce que cette question m'a expliqué plus en détail que ce que j'ai compris à l'origine ou ne pouvait appeler à l'esprit.


Non seulement le chèque d'égalité est faux, le code est étrange. Pourquoi multipliez-vous zéro par 397? Je peux vous dire maintenant, la réponse va être zéro, alors pourquoi rendre la machine le calculer? Pourquoi xor zéro avec une valeur; C'est une opération d'identité.


Ouais, c'était bête. Je l'ai corrigé, espérons-le que c'est correct maintenant.


Devrait voir cela aussi Pourquoi-user-gethashcode-sur-égal


8 Réponses :


7
votes

Non, ce n'est pas correct, car il est pas

égalité <=> égalité de hashcode .

C'est juste

Equality => Équilibre HashCode .

ou dans l'autre sens:

inégalité de hashcode => inégalité .

citating http://msdn.microsoft.com/fr -us / bibliothèque / system.object.gethashcode.aspx :

Si deux objets comparent comme étant égaux, la méthode GetHashCode pour chaque objet doit renvoyer la même valeur. Toutefois, si deux objets ne comparent pas comme étant égales, les méthodes GetHashCode pour les deux objets ne doivent pas nécessairement renvoyer différentes valeurs.


0 commentaires

1
votes

Non, ce n'est pas un moyen acceptable de tester l'égalité. Il est très possible pour 2 valeurs non égales d'avoir le même code de hachage. Cela entraînerait votre mise en œuvre de égal pour renvoyer true quand il doit renvoyer false


0 commentaires

2
votes

Je dirais, sauf si vous ne le souhaitez que est égal à à moyenne "a le même code de hash que" pour votre type, alors non , car deux chaînes peuvent être différentes Mais partagez le même code de hachage. La probabilité peut être petite, mais ce n'est pas zéro.


0 commentaires

1
votes

Vous pouvez appeler gethashcode code> pour déterminer si les éléments sont pas em> égaux, mais si deux objets renvoient le même code de hachage, cela ne signifie pas qu'ils sont sont em> égal. Deux éléments peuvent avoir le même code de hachage mais ne pas être égaux.

S'il est coûteux de comparer deux éléments, vous pouvez comparer les codes de hachage. S'ils sont inégaux, vous pouvez alors renflouer. Sinon (les codes de hachage sont égaux), vous devez faire la comparaison complète. P>

Par exemple: P>

public override bool Equals(object obj)
  {
    Class1 other = obj as Class1;
    if (other == null || other.GetHashCode() != this.GetHashCode())
        return false;
    // the hash codes are the same so you have to do a full object compare.
  }


2 commentaires

Avec de nombreux objets, cela aura tendance à être plus lent que d'utiliser la comparaison intégrée. Si les objets sont égaux, vous finissez par faire une comparaison complète et A gethascode . S'ils ne sont pas égaux, vous finissez par appeler à gethashcode , qui lit probablement dans l'objet entier. est égal à , d'autre part, ne lit probablement que suffisamment de l'objet pour déterminer que les objets ne sont pas égaux. Cela étant dit, dans le cas d'objets compliqués qui sont lents à comparer, mais ont une méthode gethashcode (par exemple parce qu'il est calculé à l'avance), cette optimisation aidera beaucoup.


@Brian, je conviens que c'est rarement utile pour les raisons que vous dites. Je ne pense pas non plus précomptes gethashcode est souvent utile (comme étant rarement utilisé, en particulier si vous utilisez un IéqualityComparer implémentation plutôt que le gethashcode par défaut < / code>). Cependant, voir ma réponse pour un cas où le fait que le hashcode est stocké de toute façon (pour d'autres raisons) peut donner un sens à l'approche de Jim.



1
votes

vous ne peut pas dire que simplement parce que les codes de hachage sont égaux, les objets doivent être égaux.

La seule fois que vous appelez gethashcode à l'intérieur de est égal à s'il était beaucoup moins cher pour calculer une valeur de hachage pour un objet (disons, parce que vous le mettez en cache) que vérifier l'égalité. Dans ce cas, vous pourriez dire si (ceci.gethashcodecode ()! = Autre.GetHashCode ()) Renvoie FAUX; afin que vous puissiez vérifier rapidement que les objets n'étaient pas égaux.

Alors, quand allez-vous faire cela? J'ai écrit un certain code qui prend des captures d'écran à intervalles périodiques et tente de trouver combien de temps cela a été depuis que l'écran a changé. Étant donné que mes captures d'écran sont de 8 Mo et ont relativement peu de pixels qui changent dans l'intervalle de capture d'écran, il est assez coûteux de rechercher une liste d'entre eux de trouver les mêmes. Une valeur de hachage est petite et doit être calculée une fois par capture d'écran, ce qui facilite l'élimination des personnes non égales connues. En fait, dans ma demande, j'ai décidé que d'avoir des haubes identiques était suffisamment proche d'être égal à ce que je n'avais même pas la peine de mettre en œuvre le surcharge , causant le compilateur C # pour me prévenir que je surchargeait < Code> gethashcode sans surcharge est égal à .


0 commentaires

15
votes

Les autres ont raison; Votre opération d'égalité est cassée. Pour illustrer:

public static void Main()
{
    var c1 = new Class1() { A = "apahaa", B = null };
    var c2 = new Class1() { A = "abacaz", B = null };
    Console.WriteLine(c1.Equals(c2));
}


0 commentaires

0
votes

Il y a un cas où l'utilisation de Hashcodes comme une coupe courte sur les comparaisons à l'égalité a du sens.

Considérez le cas où vous construisez une hache ou un hashset. En fait, considérons simplement des hashèsets (les hashables étendent qu'en tenant également une valeur, mais qui n'est pas pertinente).

Il existe différentes approches que l'on peut prendre, mais dans tous, vous avez un petit Nombre de machines à sous les valeurs hachées peuvent être placées et nous prenons l'approche ouverte ou fermée (qui juste pour le plaisir, certaines personnes utilisent le jargon opposé pour les autres); Si nous entrons en collision sur la même fente pour deux objets différents, nous pouvons les stocker dans la même fente (mais avoir une liste liée ou telle pour l'endroit où les objets sont réellement stockés) ou en rééchangeant une fente différente (il y a divers Stratégies pour cela).

Maintenant, avec l'une ou l'autre approche, nous nous éloignons de la complexité O (1) que nous voulons avec une haquetable et vers une complexité O (n). Le risque de ceci est inversement proportionnel au nombre de machines à sous disponibles. Après une certaine taille, nous redimensionnons la haquetable (même si tout était idéal, nous devions finalement faire cela si le nombre d'articles stockés était supérieur au nombre de Slots).

Ré-insertion des éléments sur un redimensionnement dépendra évidemment des codes de hachage. À cause de cela, alors qu'il est rarement logique de mémoise gethascode () dans un objet (il n'est tout simplement pas appelé assez souvent sur la plupart des objets), il est certainement logique de le souvenir dans la table de hachage lui-même (ou peut-être, à mémoter un résultat produit, tel que si vous re-déduisez avec un hachage de Wang / Jenkins afin de réduire les dommages causés par Bad gethashcode () implémentations).

Maintenant, quand on vient insérer notre logique va être quelque chose comme:

  1. Obtenez le code de hachage pour objet.
  2. Obtenez la fente pour l'objet.
  3. Si la fente est vide, placez l'objet dedans et retournez.
  4. Si la fente contient un objet égal, nous avons terminé un hashset et avons la position de remplacer la valeur d'une hache. Faites cela et retournez.
  5. Essayez la prochaine fente selon la stratégie de collision et revenez au point 3 (redimensionner peut-être si nous nous en bouge trop souvent).

    Donc, dans ce cas, nous devons obtenir le code de hachage avant de comparer pour l'égalité. Nous avons également le code de hachage des objets existants déjà pré-calculés pour permettre le redimensionnement. La combinaison de ces deux faits signifie qu'il est logique de mettre en œuvre notre comparaison du point 4 comme: xxx

    évidemment, l'avantage de cela dépend de la complexité du _cmp .Equals . Si notre type de clé était int , ce serait un déchet total. Si notre type de clé où la chaîne et que nous utilisions des comparaisons d'égalité normalisées de casse-insensibles (de sorte qu'il ne peut même pas être raccourci de longueur), la sauvegarde pourrait bien valoir la peine.

    Mémo-mémoire code de hachage Il est de sens parce qu'ils ne sont pas utilisés assez souvent pour être une victoire de performance, mais les stocker dans le hashset ou la hache elle-même peut avoir un sens.


0 commentaires

0
votes
  1. C'est une mauvaise mise en œuvre, car d'autres ont déclaré pourquoi. p> li>

  2. Vous devriez court-circuiter la vérification de l'égalité à l'aide de gethashcode code> comme: p>

    var watch = Stopwatch.StartNew();
    for (int i = 0; i < 100000; i++) 
    {
        action(); //Equals and GetHashCode called here to test for performance.
    }
    watch.Stop();
    Console.WriteLine(watch.Elapsed.TotalMilliseconds);
    


0 commentaires