如何使用HashSet <mycustomclass>删除MyCustomClass的重复项?</mycustomclass>

时间:2010-06-20 17:59:16

标签: c# c#-3.0

我有HashSet<MyCustomClass> mySet = new HashSet<MyCustomClass>();,我希望删除包含相同值的所有MyCustomClass。

让我们说MyCustomClass看起来像这样:

public class MyCustomClass
{
    Point point;

    public MyCustomClass(int x, int y)
    {
        point.X = x;
        point.Y = y;
    }

    // Other methods...
}

我尝试像MSDN建议的那样实现IEqualityComparer,并将其传递给HashSet<MyCustomClass>();的构造函数,但最终失败了。

什么是正确的方法?

修改

这是我的Chain课程和我的ChainEqualityComparer

public class Chain
{
    HashSet<Mark> chain;
    HashSet<Mark> marks;

    public Chain(HashSet<Mark> marks)
    {
        chain = new HashSet<Mark>();
        this.marks = marks;
    }       
    // Other methods...
}

public class ChainEqualityComparer : IEqualityComparer<Chain>
{
    #region IEqualityComparer<Chain> 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<Mark>
{
    #region IEqualityComparer<Mark> Members

    public bool Equals(Mark x, Mark y)
    {
        return (x.X == y.X) && (x.Y == y.Y);
    }

    public int GetHashCode(Mark obj)
    {
        return obj.GetHashCode() ^ obj.GetType().GetHashCode();
    }

    #endregion
}

(如果代码太多,我可以将代码粘贴到代码中......)

2 个答案:

答案 0 :(得分:5)

您可以使用EqualityComparer或仅覆盖Equals和GetHashCode。

您必须确保您认为是重复的任何内容都被标识为具有等效的哈希码,并在测试相等时返回true。

我的猜测是你没有返回相同的哈希码。你可以发布相等比较器的代码吗?

作为测试,你可以这样做:

var set = new HashSet<MyCustomClass>();
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);

一组类似的测试也适用于相等比较器。

修改

是的,怀疑它是哈希码函数。您需要根据类型本身的值来计算它。一个常见的错误。

public int GetHashCode(Mark obj)
{
    return ((MyCustomClass)obj).point.GetHashCode();
}

假设point是您类型中唯一的州字段。

答案 1 :(得分:2)

我认为你被绊倒了因为两个Mark实例具有相同的值,在ChainEqualityComparer类中将不相等。似乎没有使用过MarkEqualityComparer

该行:

if (!y.ChainWithMarks.Contains(mark))
除非您在Equals课程上覆盖GetHashCodeMark,否则

始终为false。 (除非你在链x和链y中都有两个相同标记的引用,我认为这不是你想要的)。

如果y.ChainWithMarks是HashSet并且您想使用MarkEqualityComparer,请确保使用包含MarkEqualityComparer实例的正确构造函数创建该HashSet。

由于Mark是值类型,因此您可以考虑使用结构来表示它,因为.Net运行时在比较时使用值相等而不是引用相等。我认为这实际上是你的想法最正确的实现。