提问人:XavierAM 提问时间:6/23/2020 最后编辑:XavierAM 更新时间:6/23/2020 访问量:52
使用可变键从集合中检索项的有效方法
Efficient way of retrieving an item from a collection with a mutable key
问:
我有一个具有 FooPosition 属性的 Foos 项目集合,我需要通过它们的位置快速访问 Foos。
例如:检索位于 X=0 和 Y=1 的 Foo。
我的第一个想法是为此目的使用字典,并使用 FooPosition 作为字典键。我知道我收藏中的每个 FooPosition 都是独一无二的,如果不是这种情况,我不介意抛出一个异常。
只要 Foos 不到处移动,这就可以很好地工作。
但是,正如我想出了艰难的方法,并且由于这篇文章和这篇文章而理解,如果 FooPosition 更新,这将不再起作用。我不应该在字典中使用可变键:字典将 FooPosition HashCode 保存在内存中,但在修改底层 FooPosition 时不会更新它。因此,调用 dic[Position(0,1)] 会给我生成字典时处于此位置的 Foo。
所以,我现在想知道我应该使用什么来有效地检索 Foos 的位置。
通过高效,我的意思是每次我按位置查询 Foo 时,不要遍历整个集合。是否有合适的结构来容纳可变键?
感谢您的帮助
编辑
正如评论中正确提到的,我的问题中缺少一个部分:我无法控制 Foo Moves。该软件实际上通过COM协议连接到另一个软件(通过VSTO的Excel),该协议更改了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>
评论