无法从SortedDictionary C#

时间:2015-12-27 20:41:21

标签: c# dictionary collections iequalitycomparer icomparer

我有一个包含在SortedDictionary中的节点类:

SortedDictionary<Node, bool> openList = new SortedDictionary<Node, bool>();

我需要在节点上编写CompareTo方法,以便根据int值(F)从最低到最高对节点进行排序。我还需要能够根据字符的位置检查字典中是否已存在节点(此位置是节点唯一的原因)。 CompareTo看起来像这样:

public int CompareTo(Node other)
{
    if (GridPosition != other.GridPosition)
    {
        if (F > other.F)
        {
            return 1;
        }
        if (F < other.F)
        {
            return -1;
        }
        return -1;
    }

    return 0;
}

问题是,它并不总是返回正确的结果。例如,即使节点在字典中,以下代码行也将返回false。但是它会按照我的意愿对我添加到字典中的所有节点进行排序。

Node node = new Node(); //It has a grid position and a f value
openList.add(node, false);

if(openList.Keys.Contains(node)) //this returns false
{

} 

为了解决这个问题,我创建了一个EqualityComparer并在比较值时使用它。等式比较器如下所示:

class NodeEqualityComparer : IEqualityComparer<Node>
{
    public bool Equals(Node x, Node y)
    {
        return x.GridPosition == y.GridPosition;
    }

    public int GetHashCode(Node obj)
    {
        return obj.GridPosition.GetHashCode();
    }
}

我在SortedDictionary的Contains方法中使用此相等比较器作为参数,这样可以正常工作,并根据词典中的内容返回正确的结果:

if (openList.Keys.Contains(currentNode,new NodeEqualityComparer())) //This will return true if the node is in the dictionary
{

}

当我需要从Dictionary中删除节点时,问题就出现了。 remove函数使用Node上的CompareTo方法来查找要删除的节点,正如我之前所说,此函数在比较对象时显然没有返回正确的结果。这意味着下面的代码不会在100%的时间内从字典中删除节点。您不能将equalityComparer传递给remove函数,这样就无法修复我的问题。

   Node node = new Node(); //It has a grid position and a f value
    openList.add(node, false);
    openList.Remove(node);

也许我以错误的方式处理这个问题,所以如果有人提出解决这个问题的建议,我会非常乐意听到这些问题。也许我可以写一个解决这个问题的CompareTo函数?

1 个答案:

答案 0 :(得分:0)

这个问题可能是您在比较器中比较GridPosition的结果。 C#区分值类型和引用类型。如果比较两个int变量,则比较器将基于值进行相等。对于实例化的类,然而comparisson基于引用,这意味着您正在比较对象是否是内存中的对象。

此:

if (GridPosition != other.GridPosition)
{

可能几乎总是返回true,从而导致您的排序顺序正确,因为如果statment嵌套在内部,则提供订单:

if (F > other.F)
{
    return 1;
}
if (F < other.F)
{
    return -1;
}

但是如果(F == other.F)指定了-1,那么ContainsKey将无法将这些对象识别为相等。

根据GridPosition的类型,您应该提供适当的比较器,例如

if (GridPosition.X != other.GridPosition.X && GridPosition.Y != other.GridPosition.Y)

并且取决于F是什么,你违反了对称的数学原理,因为具有不同GridPosition和等于F的对象将总是在任何其他对象实现之前被排序。因此,对于两个对象,您可以获得A == B ==> -1B == A ==> -1,这在任何情况下都无用。

所以你必须在嵌套的if:

中这样做
if (GridPosition != other.GridPosition)
{
    if (F > other.F)
    {
        return 1;
    }
    if (F < other.F)
    {
        return -1;
    }
    /////////////////////////////////
    return 0;
    /////////////////////////////////
}

或将比较扩展到GridPositionF以外的第三个条件

编辑:根据您在评论中提供的信息,在这种情况下,您实际上并不需要字典,只需要具有正确排序的列表。例如:

        List<Node> myList = new List<Node>();
        myList.Sort((node1, node2) => node1.F > node2.F);//Sort the list based on their node value

至于你的布尔;我不知道这代表什么,但我强烈的印象是你想要一个常规的Dictionary<Node, bool>。然后使用列表myList来处理您需要的任何节点作为下一个航路点,并在需要时查找与字典中的节点相对应的bool。