簡體   English   中英

如何覆蓋 HashSet 的 Equals 和 GetHash

[英]How to override Equals and GetHash of HashSet

我有一個HashSet<int[]> foo其中 int[] 代表平面中一個點的坐標。 位置 0 處的值表示x ,位置 1 處的值表示y 我想覆蓋 Equals 和 GetHashCode 方法,以便能夠刪除一個元素(表示為大小為 2 的數組的點),如果其內部值等於給定的值。

已經嘗試過:

public override int GetHashCode(){
    return this.GetHashCode();
}

public override bool Equals(object obj){
    if (obj == null || ! (obj is int[])) 
     return false;

    HashSet<int[]> item = obj as HashSet<int[]>;

    return item == this;
}

在我的課堂迷宮。

提前致謝。

編輯

我找到了一種方法來做到這一點

class SameHash : EqualityComparer<int[]>
{
    public override bool Equals(int[] i1, int[] i2)
    {
        return i1[0] == i2[0] && i1[1] == i2[1]; 
    }


    public override int GetHashCode(int[] i)
    {
        return base.GetHashCode();
    }
}

看起來您似乎解決了您所要求的問題,但有一些重要的事情需要指出。 當您實現EqualityComparer<int[]>您將GetHashCode(int[] i)編碼為return base.GetHashCode(); 即使它有效,這也是不正確的。 我花時間為您提供了下面的代碼,以便您查看您的實現結果,並且我還為您提供了一個可能的解決方案。 復制此代碼並在控制台項目中運行它。 注釋您的代碼行,取消注釋其正下方的行並再次運行它。 你會看到不同! 總而言之,當您返回base.GetHashCode()您將為每個項目返回相同的哈希碼。 這會導致所有插入的哈希集內部發生沖突,最終行為就像您使用List<int[]>一樣慢,並且您在插入之前詢問它是否包含元素。 這就是為什么您會看到,通過使用我提供給您的函數以及我生成的數字范圍,您將能夠在不到 1 秒的時間內插入多達一百萬次。 然而,使用你的,無論范圍如何,在大約一萬次插入中花費 1 秒。 發生這種情況是因為對於所有 n 次插入都存在沖突,並且當 HashSet 和均勻分布的哈希函數的預期為 O(n) 時,由此產生的時間復雜度為 O(n^2)。 看一下這個:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace hashExample
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int[]> points = new List<int[]>();
            Random random = new Random();
            int toInsert = 20000;
            for (int i = 0; i < toInsert; i++)
            {
                int x = random.Next(1000);
                int y = random.Next(1000);
                points.Add(new int[]{ x,y });
            }
            HashSet<int[]> set = new HashSet<int[]>(new SameHash());
            Stopwatch clock = new Stopwatch();
            clock.Start();
            foreach (var item in points)
            {
                set.Add(item);
            }
            clock.Stop();
            Console.WriteLine("Elements inserted: " + set.Count + "/" + toInsert);
            Console.WriteLine("Time taken: " + clock.ElapsedMilliseconds);
        }

        public class SameHash : EqualityComparer<int[]>
        {
            public override bool Equals(int[] p1, int[] p2)
            {
                return p1[0] == p2[0] && p1[1] == p2[1];
            }
            public override int GetHashCode(int[] i)
            {
                return base.GetHashCode();
                //return i[0] * 10000 + i[1];
                //Notice that this is a very basic implementation of a HashCode function
            }
        }    
    }
}

我發現它可能的唯一方法是創建一個類 MyPair 而不是像你那樣使用數組 (int[])。 請注意,我在 GetHashCode() 函數中使用了 X*10000 + Y,但您可以更改常量值以便為每個項目獲得更好的 HashCode,或者您可以創建自己的。 我只是提供這個作為一個簡單的例子,因為當 X 和 Y 的邊界相對較小(小於 Int.MaxValue 的根)時,這是一種使用不同 hashCode 的簡單方法。 在這里你有工作代碼:

using System;
using System.Collections.Generic;
using System.Linq;

namespace hash
{

    public class MyPair
    {
        public int X { get; set; }
        public int Y { get; set; }

        public override int GetHashCode()
        {
            return X * 10000 + Y;
        }

        public override bool Equals(object obj)
        {
            MyPair other = obj as MyPair;
            return X == other.X && Y == other.Y;
        }
    }

    class Program
    {

        static void Main(string[] args)
        {
            HashSet<MyPair> hash = new HashSet<MyPair>();
            MyPair one = new MyPair { X = 10, Y = 2 };
            MyPair two = new MyPair { X = 1, Y = 24 };
            MyPair three = new MyPair { X = 111, Y = 266 };
            MyPair copyOfOne = new MyPair { X = 10, Y = 2 };
            Console.WriteLine(hash.Add(one));
            Console.WriteLine(hash.Add(two));
            Console.WriteLine(hash.Add(three));
            Console.WriteLine(hash.Add(copyOfOne));
        }  

    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM