c# - 从字典中检索原始 key

标签 c# dictionary

有没有办法直接从 C# 字典访问原始键对象(其中键是引用类型)?我在另一个网站 ( http://www.pcreview.co.uk/forums/get-original-key-object-dictionary-t3351718.html ) 上看到过这个问题,并且由于大多数响应者不明白为什么这是一个合理的问题/不是糟糕的底层设计的症状,我在下面提供了背景细节。

目前我的解决方法是:

(a) 遍历键检查是否相等,复杂度为 O(n) :(

(b) 维护一个额外的实习生池(例如,另一个将键映射到自身的字典)。这使我们达到 O(1) 的复杂度,但需要额外的内存,将项目添加到字典时的额外工作,无法正确协调的风险......这些都不是致命的,但它并不理想,如果Dictionary<>提供了一种通过key检索key的方法。

具体来说,我有一个表示状态图的 Dictionary< State, List< State>>:每个键表示状态机的一个状态,关联的值是从那里可直接到达的相邻状态列表。例如状态可以表示棋盘的配置,而相邻状态将是一步可及的配置。

我通过从初始状态开始构建状态图来填充状态图,构建邻居列表,然后递归调用每个邻居的填充例程。在每个阶段,算法都会检查邻居状态是否已经是 Dictionary 中的键(否则我们永远不会完成)。 State 是一个引用类型(即类),具有重写的 GetHashCode 和 Equals 方法。

从语义上讲,这工作正常。但是现在邻居列表是状态的不同副本而不是原始副本,所以如果有 N 个状态,每个状态平均有 M 个邻居,我们在内存中有 NxM 个 State 对象,而实际上我们只需要 N 个 State 对象和 NxM 个对 State 对象的引用。除了会增加内存占用之外,它还会使相等性测试变慢,因为您无法从 Equals() 中的引用相等性快捷方式中获益。

从评论来看,问题似乎并不清楚,所以这里有一些伪代码可以更好地说明它:

public class StateGraphExample
{
    public static void Main()
    {
        State initialState = State.GetInitialState();
        var graph = new Dictionary<State, List<State>>();
        BuildGraph(initialState, graph);
    }

    public static void BuildGraph(State state, Dictionary<State, List<State>> graph)
    {
        var neighbours = new List<State>();

        foreach (State.Move move in state.GetValidMoves())
            neighbours.Add(state.ApplyMove(move));

        graph[state] = neighbours;

        foreach (State neighbour in neighbours)
            if (!graph.ContainsKey(neighbour))
                BuildGraph(neighbour, graph);
    }

    public class State
    {
        //Lots of data members here...

        public static State GetInitialState()
        { /* Return State object representing initial state... */ }

        public class Move
        { /* Representation of a move that takes us from one State to another... */ }

        public List<State.Move> GetValidMoves()
        { /* Return valid moves from this State object... */ }

        public State ApplyMove(State.Move move)
        { /* Clones this State object, applies move to it and returns the result... */ }

        public override int GetHashCode()
        { /* Compute hash... */ }

        public override bool Equals(object obj)
        { /* Test equality... */ }

        private State Clone()
        { /* Clone self... */ }
    }
}

最佳答案

您可以创建一个State 的“池”,然后在创建时使用现有的(如果已经创建的话)。示例:

class Sample : IEquatable<Sample>
{
  private int _params;
  private Sample(int params) { _params = params; }

  private static HashSet<Sample> _samples = new HashSet<Sample>();

  public static GetSample(int params)
  {
    Sample s = new Sample(params);
    if (!_samples.ContainsKey(s))
      _samples.Add(s);

    return _samples[s];
  }
}

关于c# - 从字典中检索原始 key ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10432353/

相关文章:

c# - Rdlc tablix 列标题未在每一页上重复 "Repeat column header on every page"已检查

python - 需要一个 defaultdict,其值为两个列表

c++ - 使用列表c++在 map 中查找元素

c++ - std::map 是否分配它的比较器?

c# - ExternalException (0x80004005) GDI+ 中发生一般性错误

c# - 合并内存流以在 C# 中创建 http PDF 响应

python - 将列表转换为 DataFrame 并在 DataFrame 列内拆分嵌套字典 - Python 3.6

java - 构建器模式中的初始化程序错误异常

c# - 使用 directx 在 c# 中学习图形的最佳方法是什么

c# - 无法在 web.config 中为 WCF Web 服务设置服务名称属性