使用可变键从 collection 检索项目的有效方法
Efficient way of retrieving an item from a collection with a mutable key
我有 collection 个项目 Foos,其中 属性 FooPosition,我需要通过他们的位置快速访问 Foos。
例如:检索位于 X=0 和 Y=1 的 Foo。
我的第一个想法是为此目的使用字典并使用 FooPosition 作为字典键。我知道我的 collection 中的每个 FooPosition 都是唯一的,如果不是这样,我不介意抛出异常。
只要 Foos 不到处乱动就可以正常工作。
但是,由于我找到了困难的方法,并且由于 and this 的帖子而理解,如果 FooPosition 更新,这将不再起作用。 我不应该在字典中使用可变键:字典将 FooPosition HashCode 保留在内存中,但不会在底层 [=35] 时更新它=]FooPosition被修改。因此,调用 dic[Position(0,1)] 给我 Foo ,它在构建字典时处于这个位置。
所以,我现在想知道我应该使用什么来有效地检索 Foos 的位置。
我所说的高效是指每次按位置查询 Foo 时不会遍历整个 collection。是否有适合可变键的结构?
感谢您的帮助
编辑
正如评论中正确提到的那样,我的问题中缺少了一部分:我无法控制 Foo 移动。该软件实际上通过 COM 协议连接到另一个软件(Excel 通过 VSTO),该协议更改 FooPosition(Excel 范围)而不通知更改。
因此,如果发生移动,我无法采取任何行动,因为我不知道确实发生了变化。
public class FooManager
{
public void DoSomething(IList<Foo> foos) {
Dictionary<FooPosition, Foo> fooPositionDictionary = foos.ToDictionary(x => x.Position, x => x); //I know that position is unique
//Move Foos all around the place by changing their positions.
FooPosition queryPosition = new FooPosition(0, 1);
fooPositionDictionary.TryGetValue(queryPosition, out var foo1); //DOES NOT WORK
var foo2 = foos.FirstOrDefault(x => x.Position == queryPosition); //NOT EFFICIENT
//Any better idea?
}
}
public class Foo
{
public string Name { get; set; }
public FooPosition Position { get; set; }
}
public class FooPosition : IEquatable<FooPosition>
{
public int X { get; set; }
public int Y { get; set; }
public FooPosition(int x, int y)
{
X = x;
Y = y;
}
public void MoveBy(int i)
{
X = X + i;
Y = Y + i;
}
public bool Equals(FooPosition other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return X == other.X && Y == other.Y;
}
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((FooPosition) obj);
}
public override int GetHashCode()
{
unchecked
{
return (X * 397) ^ Y;
}
}
public static bool operator ==(FooPosition left, FooPosition right)
{
return Equals(left, right);
}
public static bool operator !=(FooPosition left, FooPosition right)
{
return !Equals(left, right);
}
}
在某种意义上,字典 - 与任何其他基于散列的数据存储一样 - 使用某种缓存。在这种情况下,哈希被缓存。然而,对于每个缓存,您都需要一些 常量 数据,这些数据在该数据存储的生命周期内不会改变。如果没有这样的常量数据,就无法有效地缓存该数据。
所以你最终将所有项目存储在某个线性集合中 - 例如a List<T>
- 并一次又一次地迭代该列表。
我有 collection 个项目 Foos,其中 属性 FooPosition,我需要通过他们的位置快速访问 Foos。
例如:检索位于 X=0 和 Y=1 的 Foo。
我的第一个想法是为此目的使用字典并使用 FooPosition 作为字典键。我知道我的 collection 中的每个 FooPosition 都是唯一的,如果不是这样,我不介意抛出异常。
只要 Foos 不到处乱动就可以正常工作。
但是,由于我找到了困难的方法,并且由于
所以,我现在想知道我应该使用什么来有效地检索 Foos 的位置。
我所说的高效是指每次按位置查询 Foo 时不会遍历整个 collection。是否有适合可变键的结构?
感谢您的帮助
编辑
正如评论中正确提到的那样,我的问题中缺少了一部分:我无法控制 Foo 移动。该软件实际上通过 COM 协议连接到另一个软件(Excel 通过 VSTO),该协议更改 FooPosition(Excel 范围)而不通知更改。
因此,如果发生移动,我无法采取任何行动,因为我不知道确实发生了变化。
public class FooManager
{
public void DoSomething(IList<Foo> foos) {
Dictionary<FooPosition, Foo> fooPositionDictionary = foos.ToDictionary(x => x.Position, x => x); //I know that position is unique
//Move Foos all around the place by changing their positions.
FooPosition queryPosition = new FooPosition(0, 1);
fooPositionDictionary.TryGetValue(queryPosition, out var foo1); //DOES NOT WORK
var foo2 = foos.FirstOrDefault(x => x.Position == queryPosition); //NOT EFFICIENT
//Any better idea?
}
}
public class Foo
{
public string Name { get; set; }
public FooPosition Position { get; set; }
}
public class FooPosition : IEquatable<FooPosition>
{
public int X { get; set; }
public int Y { get; set; }
public FooPosition(int x, int y)
{
X = x;
Y = y;
}
public void MoveBy(int i)
{
X = X + i;
Y = Y + i;
}
public bool Equals(FooPosition other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return X == other.X && Y == other.Y;
}
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((FooPosition) obj);
}
public override int GetHashCode()
{
unchecked
{
return (X * 397) ^ Y;
}
}
public static bool operator ==(FooPosition left, FooPosition right)
{
return Equals(left, right);
}
public static bool operator !=(FooPosition left, FooPosition right)
{
return !Equals(left, right);
}
}
在某种意义上,字典 - 与任何其他基于散列的数据存储一样 - 使用某种缓存。在这种情况下,哈希被缓存。然而,对于每个缓存,您都需要一些 常量 数据,这些数据在该数据存储的生命周期内不会改变。如果没有这样的常量数据,就无法有效地缓存该数据。
所以你最终将所有项目存储在某个线性集合中 - 例如a List<T>
- 并一次又一次地迭代该列表。