字典键作为返回 KeyNotFoundError 的对象

发布于 2025-01-09 19:42:46 字数 2100 浏览 0 评论 0原文

我正在尝试在 Unity 中实现 Dijkstras 寻路算法。我有一个字典distances,其中包含从GridData.WalkableNodes 获得的所有可能行走的节点。当尝试获取给定节点的已找到邻居的距离时,由于某种原因,我无法从 distances 字典中获取距离值。它给了我一个 KeyNotFoundError 。我是否做错了什么但使用 Node 对象作为键?在我的测试中,您可以使用对象作为从字典中检索值的键,因此我认为这不是问题。

脚本文件可以在pastebin上看到 GridData.cs Dijkstra.cs

Dictionary<Node, int> distances = GridData.WalkableCells.ToDictionary(x => x, x => int.MaxValue);

foreach (Node neighbour in neighbours)
{

    if (!visited.Contains(neighbour.Position))
    {
        int dist = distances[currentCell] + 1;

        if (dist < distances[neighbour]) // Key not found happens here!
        {
            distances[neighbour] = dist;

            priorityQueue.Enqueue(neighbour, dist);
            visited.Add(neighbour.Position);

            neighbour.parentNode = currentCell;
            parents.Add(neighbour);
        }
    }
}

如果我使用 Vector3 而不是 Node 作为密钥,它似乎可以工作,但我不明白为什么它在使用 Node.js 时不起作用?

Dictionary<Vector3, int> distances = GridData.WalkableCells.ToDictionary(x => x.Position, x => int.MaxValue);

foreach (Node neighbour in neighbours)
{

    if (!visited.Contains(neighbour.Position))
    {
        int dist = distances[currentNode.Position] + 1;

        if (dist < distances[neighbour.Position]) 
        {
            distances[neighbour.Position] = dist;

            priorityQueue.Enqueue(neighbour, dist);
            visited.Add(neighbour.Position);

            neighbour.parentNode = currentCell;
            parents.Add(neighbour);
        }
    }
}

节点类

public class Node
{
    public Vector3 Position { get; set; }
    public CellType CellType { get; set; }
    public int Cost { get; set; }
    public Node parentNode {get; set;}

public Node(Vector3 position, CellType cellType, int cost)
{
    Position = position;
    CellType = cellType;
    Cost = cost;
}
}

I am trying to implement Dijkstras path finding algorithm in Unity. I have a dictionary distances containing all the possible Nodes that can be walked on which is obtained from GridData.WalkableNodes. When trying to obtain the distance of the found neighbours for a given Node, I am not able to obtain the distance value from the distances dictionary for some reason. It gives me a KeyNotFoundError. Am I doing something wrong but using the Node object as the key? In my testing, you can use an Object as the key to retrieve a value from a dictionary so I do not think this is the issue.

Script files can be seen on pastebin
GridData.cs
Dijkstra.cs

Dictionary<Node, int> distances = GridData.WalkableCells.ToDictionary(x => x, x => int.MaxValue);

foreach (Node neighbour in neighbours)
{

    if (!visited.Contains(neighbour.Position))
    {
        int dist = distances[currentCell] + 1;

        if (dist < distances[neighbour]) // Key not found happens here!
        {
            distances[neighbour] = dist;

            priorityQueue.Enqueue(neighbour, dist);
            visited.Add(neighbour.Position);

            neighbour.parentNode = currentCell;
            parents.Add(neighbour);
        }
    }
}

If I use Vector3 instead of a Node as the key, it seems to work but I do not understand why it does not work when using Node.

Dictionary<Vector3, int> distances = GridData.WalkableCells.ToDictionary(x => x.Position, x => int.MaxValue);

foreach (Node neighbour in neighbours)
{

    if (!visited.Contains(neighbour.Position))
    {
        int dist = distances[currentNode.Position] + 1;

        if (dist < distances[neighbour.Position]) 
        {
            distances[neighbour.Position] = dist;

            priorityQueue.Enqueue(neighbour, dist);
            visited.Add(neighbour.Position);

            neighbour.parentNode = currentCell;
            parents.Add(neighbour);
        }
    }
}

Node class

public class Node
{
    public Vector3 Position { get; set; }
    public CellType CellType { get; set; }
    public int Cost { get; set; }
    public Node parentNode {get; set;}

public Node(Vector3 position, CellType cellType, int cost)
{
    Position = position;
    CellType = cellType;
    Cost = cost;
}
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

够钟 2025-01-16 19:42:46

您正在使用 new Node 来填充哈希图和列表。

因此,这些新创建的Node当然与添加到字典中的实例不完全相同

它适用于 Vector3 因为它实现了 IEquatable< ;Vector3> 以及 GetHashCode

如果您没有显式重写 Equals ,则默认情况下 使用引用相等(请参阅object.Equals


您应该简单地使用位置作为键,因为正如您已经发现的那样,它已经实现了它。或者只需确保也实现它并使用该位置作为哈希代码提供程序:

public class Node : IEquatable<Node>
{
    public Vector3 Position { get; set; }
    public CellType CellType { get; set; }
    public int Cost { get; set; }
    public Node parentNode {get; set;}

    public Node(Vector3 position, CellType cellType, int cost)
    {
        Position = position;
        CellType = cellType;
        Cost = cost;
    }

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

    public bool Equals(Node other)
    {
        if (ReferenceEquals(null, other))
        {
            return false;
        }

        if (ReferenceEquals(this, other))
        {
            return true;
        }

        return GetHashCode() == other.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }

        if (ReferenceEquals(this, obj))
        {
            return true;
        }

        if (obj.GetType() != this.GetType())
        {
            return false;
        }

        return Equals((Node)obj);
    }
}

如果您还想考虑其他属性,例如 CelltypeCost 等,并且可以 简单地扩展它。

public override int GetHashCode()
{
    return HashCode.Combine(Position, Cost, CellType);
}

在同一位置有多个节点,您可以根据您的需要

You are using new Node to fill your hashmap and lists.

Therefore these newly crated Nodes are o course not the exact same instances as the ones added into your dictionary!

It works for Vector3 because it implements IEquatable<Vector3> and also GetHashCode.

If you don't explicitly override Equals then by default reference equality is used (see object.Equals)


You should either simply use the positions as keys since as you already figured out it already implements it. Or just make sure to implement it as well and use the position as hash code provider:

public class Node : IEquatable<Node>
{
    public Vector3 Position { get; set; }
    public CellType CellType { get; set; }
    public int Cost { get; set; }
    public Node parentNode {get; set;}

    public Node(Vector3 position, CellType cellType, int cost)
    {
        Position = position;
        CellType = cellType;
        Cost = cost;
    }

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

    public bool Equals(Node other)
    {
        if (ReferenceEquals(null, other))
        {
            return false;
        }

        if (ReferenceEquals(this, other))
        {
            return true;
        }

        return GetHashCode() == other.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }

        if (ReferenceEquals(this, obj))
        {
            return true;
        }

        if (obj.GetType() != this.GetType())
        {
            return false;
        }

        return Equals((Node)obj);
    }
}

if you want to take the other properties like Celltype and Cost etc also into account and can have multiple nodes on the same position you can simply extend it doing e.g.

public override int GetHashCode()
{
    return HashCode.Combine(Position, Cost, CellType);
}

according to your needs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文