如何使用HashSet 删除MyCustomClass的重复项?
我有一个HashSet mySet = new HashSet();
我希望删除包含相同值的所有MyCustomClass。
假设MyCustomClass看起来像这样:
public class MyCustomClass { Point point; public MyCustomClass(int x, int y) { point.X = x; point.Y = y; } // Other methods... }
我尝试像MSDN建议的那样实现IEqualityComparer
,并将其传递给HashSet();
的构造函数HashSet();
但我最终失败了。
什么是正确的方法?
编辑:
这是我的Chain
类和我的ChainEqualityComparer
:
public class Chain { HashSet chain; HashSet marks; public Chain(HashSet marks) { chain = new HashSet(); this.marks = marks; } // Other methods... } public class ChainEqualityComparer : IEqualityComparer { #region IEqualityComparer Members public bool Equals(Chain x, Chain y) { if (x.ChainWithMarks.Count == y.ChainWithMarks.Count) { foreach (Mark mark in x.ChainWithMarks) { if (!y.ChainWithMarks.Contains(mark)) return false; } return true; } return false; } public int GetHashCode(Chain obj) { return obj.GetHashCode() ^ obj.GetType().GetHashCode(); } #endregion }
这是我的Mark
课程:
public class Mark { int x; int y; public Mark(int x, int y) { this.x = x; this.y = y; } public int X { get { return x; } set { x = value; } } public int Y { get { return y; } set { y = value; } } } public class MarkEqualityComparer : IEqualityComparer { #region IEqualityComparer Members public bool Equals(Mark x, Mark y) { return (xX == yX) && (xY == yY); } public int GetHashCode(Mark obj) { return obj.GetHashCode() ^ obj.GetType().GetHashCode(); } #endregion }
(如果代码太多,我可以将代码粘贴到代码中……)
您可以使用EqualityComparer或仅覆盖Equals和GetHashCode。
您必须确保将您认为是重复的任何内容标识为具有等效的哈希码,并在测试相等时返回true。
我的猜测是你没有返回相同的哈希码。 你可以发布相等比较器的代码吗?
作为测试,您可以:
var set = new HashSet(); var a = new MyCustomClass(1,2); var b = new MyCustomClass(1,2); set.Add(a); set.Add(b); Assert.IsTrue(a.Equals(b)); Assert.IsTrue(b.Equals(a)); Assert.AreEqual(a.GetHashCode(), b.GetHashCode()); Assert.AreEqual(1, set.Count);
一组类似的测试也适用于相等比较器。
编辑
是的,怀疑它是哈希码function。 您需要根据类型本身的值来计算它。 一个常见的错误。
public int GetHashCode(Mark obj) { return ((MyCustomClass)obj).point.GetHashCode(); }
假定point
是您类型中唯一的状态字段。
我认为你被绊倒了因为两个具有相同值的Mark
实例在你的ChainEqualityComparer
类中是不相等的。 看起来似乎没有使用过MarkEqualityComparer
。
这条线:
if (!y.ChainWithMarks.Contains(mark))
除非您在Mark
类上重写Equals
和GetHashCode
,否则将始终为false。 (除非你在链x和链y中都有两个相同标记的引用,我认为这不是你想要的)。
如果y.ChainWithMarks
是HashSet并且您想要使用MarkEqualityComparer
,请确保使用MarkEqualityComparer
实例的正确构造函数创建该HashSet。
由于Mark
是值类型,因此您可以考虑使用结构来表示它,因为.Net运行时在比较时使用值相等而不是引用相等。 我认为这实际上是你的想法最正确的实现。