从字典中检索原始密钥

时间:2012-05-03 13:24:36

标签: c# dictionary

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

我到目前为止的解决方法是:

(a)迭代检查相等性的密钥,即O(n)复杂度:(

(b)维护一个额外的实习池(例如另一个将键映射到自己的字典)。这使我们达到了O(1)的复杂性,但需要额外的内存,当项目被添加到字典中时需要额外的工作,未能使这种协调失败的风险......这些都不是致命的,但它并不理想,如果字典<>提供了一种按密钥检索密钥的方法。

具体来说,我有一个字典<州,名单<国家>>表示状态图:每个键表示状态机的状态,相关值是从那里可直接到达的邻居状态列表。例如国家可以代表国际象棋棋盘的配置,邻国将是一次移动可以达到的配置。

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

从语义上讲,这很好用。但是现在邻居列表是状态的不同副本而不是原始副本,所以如果有N个状态平均每个M个邻居,我们在内存中有NxM State对象,当我们真的只需要N个状态对象和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... */ }
    }
}

1 个答案:

答案 0 :(得分:2)

您可以创建一个游泳池&#39; State的{​​{1}},然后,在创建时,如果已经创建了一个,则使用现有的。样品:

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];
  }
}