繁体   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