如何重写HashSet的Equals和GetHash

时间:2017-10-20 03:09:21

标签: c#

我有一个-(void)viewDidLoad { [super viewDidLoad]; [self.tabBar setItemPositioning:UITabBarItemPositioningFill]; } ,其中int []表示平面中某个点的坐标。位置0的值表示 x ,位置1的值表示 y 。我想覆盖Equals和GetHashCode方法,以便能够删除一个元素(表示为大小为2的数组的点),如果它的内部值等于给定的元素。

已经尝试过:

HashSet<int[]> foo

在我班上迷宫。

提前致谢。

修改

我找到了一种方法

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;
}

2 个答案:

答案 0 :(得分:2)

似乎你解决了你所要求的问题,但有一些重要的事情需要指出。当您实施EqualityComparer<int[]>后,您将GetHashCode(int[] i)编码为return base.GetHashCode();即使有效也不正确。我花时间为您提供以下代码,以便您查看实施结果,我还为您提供了可能的解决方案。 复制此代码并在Console Project中运行它。注释您的代码行,取消注释它下面的行并再次运行它。你会看到差异! 总结一下,当您返回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
            }
        }    
    }
}

答案 1 :(得分:1)

我发现它的唯一方法是创建一个MyPair类而不是像你一样使用数组(int [])。请注意,我在GetHashCode()函数中使用了X * 10000 + Y,但您可以更改常量值,以便为每个项目获得更好的HashCode,或者您可以创建自己的HashCode。我刚刚提供了这个作为一个简单的例子,因为当X和Y的边界相对较小(小于Int.MaxValue的根)时,这是一种简单的方法来使用不同的hashCodes。 这里有工作代码:

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));
        }  

    }
}