字典键作为对象返回 KeyNotFoundError
Dictionary Key as object returning KeyNotFoundError
我正在尝试在 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 时它不起作用。
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);
}
}
}
节点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;
}
}
您正在使用 new Node
来填充哈希图和列表。
因此,这些新创建的 Node
当然不是 与添加到您的字典中的实例 完全相同的实例!
它适用于 Vector3
,因为它实现了 IEquatable<Vector3>
and also GetHashCode
。
如果您没有明确覆盖 Equals
,则默认情况下 reference equality is used (see 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);
}
}
如果你想考虑其他属性,如 Celltype
和 Cost
等,并且可以在同一位置有多个节点,你可以简单地扩展它,例如
public override int GetHashCode()
{
return HashCode.Combine(Position, Cost, CellType);
}
根据您的需要。
我正在尝试在 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 时它不起作用。
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);
}
}
}
节点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;
}
}
您正在使用 new Node
来填充哈希图和列表。
因此,这些新创建的 Node
当然不是 与添加到您的字典中的实例 完全相同的实例!
它适用于 Vector3
,因为它实现了 IEquatable<Vector3>
and also GetHashCode
。
如果您没有明确覆盖 Equals
,则默认情况下 reference equality is used (see 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);
}
}
如果你想考虑其他属性,如 Celltype
和 Cost
等,并且可以在同一位置有多个节点,你可以简单地扩展它,例如
public override int GetHashCode()
{
return HashCode.Combine(Position, Cost, CellType);
}
根据您的需要。