【问题标题】:How to iterate in reverse through an OrderedDictionary如何通过 OrderedDictionary 反向迭代
【发布时间】:2017-06-02 17:05:43
【问题描述】:

如何反向遍历 OrderedDictionary 并访问其密钥?

由于它不支持 LINQ 扩展,我尝试了以下方法:

var orderedDictionary= new OrderedDictionary();
orderedDictionary.Add("something", someObject);
orderedDictionary.Add("another", anotherObject);

for (var dictIndex = orderedDictionary.Count - 1; dictIndex != 0; dictIndex--)
{
    // It gives me the value, but how do I get the key?
    // E.g., "something" and "another".
    var key = orderedDictionary[dictIndex];
}

【问题讨论】:

  • 以反向或正常顺序迭代它并不重要,因为正如文档所述,OrderedDictionary 的元素不按键排序,这与 SortedDictionary 类。
  • 插入顺序是我使用 OrderDictionary 的原因,我需要相应地迭代它(反向)。
  • 你总是可以遍历字典的keys属性。
  • @jdweng 但我需要根据插入顺序反向迭代字典。在该迭代期间,我需要选择键来执行其他操作。
  • 我明白了。不幸的是,这个类被过度封装了。索引器的implementation 是这样的return ((DictionaryEntry)objectsArray[index]).Value;,你需要这样的方法return ((DictionaryEntry)objectsArray[index]); 不存在。

标签: c# linq ordereddictionary


【解决方案1】:

由于它不支持 LINQ 扩展...

那是因为它是非泛型 Enumerable。您可以通过将其转换为正确的类型来使其通用:

foreach (var entry in orderedDictionary.Cast<DictionaryEntry>().Reverse()) {
    var key = entry.Key;
    var value = entry.Value;
}

【讨论】:

    【解决方案2】:

    我不关心订单事实。您可以通过将密钥复制到可索引集合来获取密钥。还需要将循环条件更改为dictIndex &gt; -1;

    请试试这个:

    var orderedDictionary = new OrderedDictionary();
    orderedDictionary.Add("something", someObject);
    orderedDictionary.Add("another", anotherObject);
    
    object[] keys = new object[orderedDictionary.Keys.Count];
    orderedDictionary.Keys.CopyTo(keys, 0);
    
    for (var dictIndex = orderedDictionary.Count-1; dictIndex > -1; dictIndex--)
    {
        // It gives me the value, but how do I get the key?
        // E.g., "something" and "another".
        var key = orderedDictionary[dictIndex];
    
        // Get your key, e.g. "something" and "another"
        var key = keys[dictIndex];
    }
    

    【讨论】:

      【解决方案3】:

      如果您需要使用 OrderdDictionary,您始终可以使用如下所示的 SortedDictionary。

      var orderedDictionary = new SortedDictionary<int, string>();
      
      orderedDictionary.Add(1, "Abacas");
      orderedDictionary.Add(2, "Lion");
      orderedDictionary.Add(3, "Zebera");
      
      var reverseList = orderedDictionary.ToList().OrderByDescending(pair => pair.Value);
      
      foreach (var item in reverseList)
      {
          Debug.Print(item.Value);
      }
      

      【讨论】:

        【解决方案4】:

        您可以像这样在索引处获取元素:

        orderedDictionary.Cast<DictionaryEntry>().ElementAt(dictIndex);
        

        为了得到Key

        orderedDictionary.Cast<DictionaryEntry>().ElementAt(dictIndex).K‌​ey.ToString();
        

        【讨论】:

        • 我会试一试,听起来很合理。
        • 注意ElementAt 的 O(n) 复杂度。因此,将其应用于集合中的每个元素将产生 o(n2) 复杂度(如果在错误的地方使用可能会非常糟糕)
        • @spender 不知道这个事实。谢谢你提出来。
        • 由于你使用的是Cast&lt;DictionaryEntry&gt;(),它变成了IEnumerable&lt;DictionaryEntry&gt;,所以你可以使用linq和foreach。不需要 ElementAt()
        【解决方案5】:

        您可以通过使用常规Dictionary(或SortedDictionary,具体取决于您的要求)来显着降低此问题的复杂性,并保留辅助List 以跟踪键的插入顺序。你甚至可以使用一个类来促进这个组织:

        public class DictionaryList<TKey, TValue>
        {
            private Dictionary<TKey, TValue> _dict;
            private List<TKey> _list;
        
            public TValue this[TKey key]
            {
                get { return _dict[key]; }
                set { _dict[key] = value; }
            }
        
            public DictionaryList()
            {
                _dict = new Dictionary<TKey, TValue>();
                _list = new List<TKey>();
            }
        
            public void Add(TKey key, TValue value)
            {
                _dict.Add(key, value);
                _list.Add(key);
            }
        
            public IEnumerable<TValue> GetValuesReverse()
            {
                for (int i = _list.Count - 1; i >= 0; i--)
                    yield return _dict[_list[i]];
            }
        }
        

        (当然还可以添加您需要的任何其他方法。)

        【讨论】:

        • 这实现了我的目标,并且对进一步自定义的限制更少。
        【解决方案6】:

        我可以建议使用SortedDictionary&lt;K, V&gt;吗?它确实支持 LINQ,并且是类型安全的:

        var orderedDictionary = new SortedDictionary<string, string>();
        orderedDictionary.Add("something", "a");
        orderedDictionary.Add("another", "b");
        
        foreach (KeyValuePair<string, string> kvp in orderedDictionary.Reverse())
        {
        }
        

        另外,正如 Ivan Stoev 在评论中指出的那样,OrderedDictionary 的返回项目根本没有排序,所以 SortedDictionary 是你想要的。

        【讨论】:

        • 我不相信字典会保持此处讨论的插入顺序:stackoverflow.com/questions/16694182/…
        • 如果顺序那么重要,为什么不把它作为关键呢?
        • 就我个人而言,我会将其分为两部分:列表和字典。当您对它进行大量迭代或拥有很多项目时,另一种转换选项可能会变得非常昂贵。
        • 是的,如果在添加字典的同时保留一个键列表,这个问题的复杂性会大大降低。您甚至可以创建一个自定义类来为您提供便利。
        • @PatrickHofman 就我个人而言,我会将其分为两部分:一个列表和一个字典。 这正是相关类在内部所做的 - 保留 ArrayListHashTable :) MS 没有创建它的通用版本,但是很容易推出你自己的版本,如果我需要它而不需要任何过度封装或限制,我会这样做 - 公开 OP 想要什么绝对没有问题,不算KeysValues 也可以有索引器这一事实。
        猜你喜欢
        • 2010-10-09
        • 1970-01-01
        • 1970-01-01
        • 2015-09-25
        • 2011-01-13
        • 2014-09-15
        • 1970-01-01
        • 1970-01-01
        • 2010-09-16
        相关资源
        最近更新 更多