C# - 使用自定义键定义hashset

时间:2013-08-06 13:27:04

标签: c# .net dictionary hashset

我在C#中使用HashSetDictionary来实现Graph结构。当HashSet键是自定义类时,HashSet元素的唯一性存在问题。我在这里:

public class Point
{
    public int x { get; set; }
    public int y { get; set; }
}

public class Vertex
{
    public Vertex(Point point)
    {
        VertexLabel = point;
    }

    public Point VertexLabel { get; private set; }
}

public class Edge
{
    public Edge(Vertex to, Vertex from, double weight)
    {
        FromVertex = from;
        ToVertex = to;
        Weight = weight;
    }

    public Vertex FromVertex { get; private set; }
    public Vertex ToVertex { get; private set; }
    public double Weight { get; private set; }
}

public class Graph
{
    public Graph()
    {
        _Vertexes = new HashSet<Vertex>();
        _VertexEdgeMapping = new Dictionary<Vertex, LinkedList<Edge>>();
    }
    private HashSet<Vertex> _Vertexes;
    private Dictionary<Vertex, LinkedList<Edge>> _VertexEdgeMapping;
}

问题在于,当我有相同的顶点并且我想将它们添加到图形时,它们会被复制。如何定义HashSet理解顶点唯一性的方法?

3 个答案:

答案 0 :(得分:26)

选项:

  • 覆盖Equals中的GetHashCodeVertex(为简单起见可能Point),很可能会随时实施IEquatable<T>
  • 创建自己的IEqualityComparer<Vertex>实现并将其传递给HashSet<Vertex>
  • 的构造函数

第一个选项很可能是最简单的,但是我强烈 强烈推荐你先使Point不可变:可变类型(或包含可变类型的类型)不能很好哈希键。我也许会把它变成struct

public struct Point : IEquatable<Point>
{
    private readonly int x, y;

    public int X { get { return x; } }
    public int Y { get { return y; } }

    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public override int GetHashCode()
    {
        return 31 * x + 17 * y; // Or something like that
    }

    public override bool Equals(object obj)
    {
        return obj is Point && Equals((Point) obj);
    }

    public bool Equals(Point p)
    {
        return x == p.x && y == p.y;
    }

    // TODO: Consider overloading the == and != operators
}

...然后覆盖GetHashCodeEquals并在IEquatable<>中实施Vertex,例如。

// Note: sealed to avoid oddities around equality and inheritance
public sealed class Vertex : IEquatable<Vertex>
{
    public Vertex(Point point)
    {
        VertexLabel = point;
    }

    public Point VertexLabel { get; private set; }

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

    public override bool Equals(object obj)
    { 
        return Equals(obj as Vertex);
    }

    public bool Equals(Vertex vertex)
    {
        return vertex != null && vertex.VertexLabel.Equals(VertexLabel);
    }
}      

答案 1 :(得分:4)

正如其他人所说,覆盖GetHashCode()类的Vertex

同时覆盖.Equals方法。字典将使用GetHashCodeEquals来确定相等。

这就是Dictionary没有替换顶点的原因。就Dictionary而言,具有相同坐标的顶点仍然根本不同。

我不会用另一个源代码示例污染你的问题,因为Jon和gzaxx已经提供了2个非常好的例子。

答案 2 :(得分:3)

覆盖GetHashCode()类的Equals()Vertex方法。

下面是示例,但您应该使用比我更好的哈希算法:)

public class Vertex
{
    public Vertex(Point point)
    {
        VertexLabel = point;
    }

    public Point VertexLabel { get; private set; }

    public override int GetHashCode()
    {
        return VertexLabel.X + VertexLabel.Y;
    }

    public override bool Equals(object obj)
    {
        //your logic for comparing Vertex
    }
}