【问题标题】:How do I reference the properties of a reference type dictionary key?如何引用引用类型字典键的属性?
【发布时间】:2013-01-26 21:23:48
【问题描述】:

我正在开发一个国际象棋引擎,我目前正在实施换位表(一组已经评估过的棋盘位置从过去的移动)。一般的想法是,当进行移动时,我会检查换位表中的匹配位置。如果存在,我会跳过代价高昂的评估过程,只从转置表中提取先前计算的结果。如果它不存在,我会进行所需的计算,然后将其添加到转置表中以供将来参考。

对我来说,这听起来像是哈希集或字典的工作。我决定用字典。我希望 key 是代表我的董事会的类,而 value 是遇到该位置的次数的 int 计数。计数的原因是能够检测到三次重复平局。如果相同的位置出现了 3 次或更多次,玩家可以选择平局。使用字典而不是哈希集,我可以通过将它与我的转置表结合起来,大大简化对三重重复绘制的检测。

为了做到这一点,我创建了代表棋盘状态的类覆盖 Equals() 和 GetHashCode()。它工作得很好,我现在能够跟踪游戏之前遇到的所有历史状态。

我的问题是我需要能够访问字典中键对象的属性。我可以查看是否存在匹配项(通过使用 .ContainsKey(...) 方法和我的 Equals()/GetHashCode() 逻辑),但现在我需要提取前面提到的计算值(存储为我的板的公共属性状态对象)来自键。

我想出了:

BoardState board = TranspositionTable.Keys.FirstOrDefault(tt => tt.GetHashCode() == this.GetHashCode());

这行得通,但对我来说感觉很笨拙。转置表的重点是加速数百万个连续棋盘状态的递归搜索。为每个匹配查询字典听起来很违反直觉。有没有更好的方法来做到这一点?

编辑:

正如已经指出的那样,由于有效的棋盘状态数量巨大,我的哈希值并不完美。我的 Equals() 覆盖检查第二个交替生成的哈希以减少冲突的可能性。我上面的“解决方案”是有缺陷的,因为它依赖于不完美的哈希。我应该使用:

BoardState board = TranspositionTable.Keys.FirstOrDefault(tt => tt.Equals(this));

我的一个愚蠢的疏忽。不过,我不喜欢查询字典。

【问题讨论】:

  • 您的字典中的关键字究竟是什么?可以使GetHashCode() 的结果成为关键吗?如果是这样,那么处理起来就更“自然”了……
  • @Yahia 哈希码,就其本质而言,并不是唯一的,因此您需要支持对象列表作为值并使用 Equals 来查找 true i> 与该哈希码相等的对象。
  • @Servy 是真的......但 OP 似乎对匹配哈希码的任何结果感到满意(根据显示的代码)......
  • 他已经实现了自己的Hashcode,所以也许它现在独一无二的? OP,是这样的吗?如果是这样......
  • @Yahia 哈希并不完美,这就是 Equals() 的用武之地。除了校验和之外,Equals() 还检查了一个校验和(第二种哈希算法)。确实,我的 lambda 没有考虑主哈希的潜在冲突。我没有考虑到这一点。我应该改用 Equals。

标签: c# dictionary key


【解决方案1】:

一种选择是只保留对字典值中键的引用,以及字典的实际值,如下所示:

Dictionary<BoardState, Tuple<BoardState, int>>

然后,每当您添加对象时,将与键相同的对象添加到值中:

Dictionary<BoardState, Tuple<BoardState, int>> boards = 
    new Dictionary<BoardState,Tuple<BoardState,int>>();
BoardState board = new BoardState();
boards.Add(board, Tuple.Create(board, 1));

另一种选择(这可能是更好的设计)是将您的板状态对象分解为两种不同的类型。有一个确实只代表棋盘的状态(这应该是不可变的),另一个保存有关该状态的其他信息,包括它发生的时间和任何其他可能适用的 mutable 属性到您的特定应用。这将阻止您访问字典键。

【讨论】:

  • 我喜欢分离状态的想法......这不是一个简单的解决方案,但感觉是正确的方向。
  • 我还应该注意,我选择了您的答案,因为您的第一个解决方案不仅回答了我的问题,而且还暗示没有简单的方法可以直接访问密钥的属性(这就是我的行为,以我自己的啰嗦方式)。顺便说一句,针对我的特殊情况的另一种解决方案是为转置表运行一个哈希集,并为三重重复规则运行一个单独的字典。这具有消除歧义的额外好处,每个人只对一件事负责。
猜你喜欢
  • 2015-11-22
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 2016-04-03
  • 1970-01-01
  • 2014-05-23
  • 1970-01-01
  • 2012-11-11
相关资源
最近更新 更多