【问题标题】:Remove elements from Dictionary<Key, Item>从 Dictionary<Key, Item> 中删除元素
【发布时间】:2012-11-13 05:23:08
【问题描述】:

我有一个字典,其中项目(例如):

  1. “A”,4
  2. “B”,44
  3. “再见”,56
  4. “C”,99
  5. “D”,46
  6. “6672”,0

我有一个列表:

  1. “A”
  2. “C”
  3. “D”

我想从我的字典中删除所有键在我的列表中的元素,最后我的字典将是:

  1. “A”,4
  2. “C”,99
  3. “D”,46

我该怎么办?

【问题讨论】:

    标签: c# list collections dictionary


    【解决方案1】:

    构造新 Dictionary 以包含列表中的元素更简单:

    List<string> keysToInclude = new List<string> {"A", "B", "C"};
    var newDict = myDictionary
         .Where(kvp=>keysToInclude.Contains(kvp.Key))
         .ToDictionary(kvp=>kvp.Key, kvp=>kvp.Value);
    

    如果修改现有字典很重要(例如,它是某个类的只读属性)

    var keysToRemove = myDictionary.Keys.Except(keysToInclude).ToList();
    
    foreach (var key in keysToRemove)
         myDictionary.Remove(key);
    

    注意 ToList() 调用 - 实现要删除的键列表很重要。如果您尝试在不具体化 keysToRemove 的情况下运行代码,您可能会遇到类似“集合已更改”的异常。

    【讨论】:

    • 两种方式的优缺点是什么?
    • @guiomie 以前的方式构造新字典,所以你有一个完整的旧字典,但以增加内存占用为代价。后来一个人就地修改了现有的字典。简而言之,如果您不是在非常庞大的字典上进行操作,则没有优缺点 - 这两种方式之间的程序状态是不等价的。
    • @J0HN 两者都会增加内存占用,因为 except() 方法实现实例化一个内部数据结构(通常是一个哈希集)以便能够在 O(n) 时间内执行操作。
    【解决方案2】:
    // For efficiency with large lists, for small ones use myList below instead.  
    var mySet = new HashSet<string>(myList);
    
    // Create a new dictionary with just the keys in the set
    myDictionary = myDictionary
                   .Where(x => mySet.Contains(x.Key))
                   .ToDictionary(x => x.Key, x => x.Value);
    

    【讨论】:

    • 你不觉得新建字典效率低吗?
    • 现在这是一个很好的问题,什么更有效,创建一个新字典,或者取出一些项目。我想这取决于所涉及的数字,很难衡量它会很有趣。
    • 这是我进行的速度测试,您的解决方案与我的不同。您可以轻松地看到创建字典更有效,因为您不会为字典中的每个元素迭代 mySet:pastebin.com/iY1LHRM1
    • 我在两个测试用例中都复制了字典,就像你有 HashSet 开销一样,我的解决方案中有第二个字典开销。令人惊讶的是,将 HashSet 排除在循环之外因此它只发生一次并没有太大变化。删除次数不如迭代次数重要。你的算法的复杂度是 O(nmT(n)),n 是字典的大小,m 是列表的大小,T(n) 是函数 Remove 所需的时间。我的是 O(m*T(n)),假设 TryGetValue 与 Remove 渐近相同。这不仅仅是执行时间,还有复杂性。你的效率很低。
    • @J0HN 人们会停止不恰当地发布此链接吗?这并不为时过早,也不是“优化”。优化是您获取代码并对其进行一些调整以使其执行速度更快的地方。这是一个完全不同的算法,你甚至不能说它为时过早,因为我这里只有 OP 的问题,我没有做他的项目。
    【解决方案3】:
    dict.Keys.Except(list).ToList()
        .ForEach(key => dict.Remove(key));
    

    【讨论】:

      【解决方案4】:

      代码:

      public static void RemoveAll<TKey, TValue>(this Dictionary<TKey, TValue> target,
                                                 List<TKey> keys)
      {
          var tmp = new Dictionary<TKey, TValue>();
      
          foreach (var key in keys)
          {
              TValue val;
              if (target.TryGetValue(key, out val))
              {
                  tmp.Add(key, val);
              }
          }
      
          target.Clear();
      
          foreach (var kvp in tmp)
          {
              target.Add(kvp.Key, kvp.Value);
          }
      }
      

      示例:

      var d = new Dictionary<string, int>
                  {
                      {"A", 4},
                      {"B", 44},
                      {"bye", 56},
                      {"C", 99},
                      {"D", 46},
                      {"6672", 0}
                  };
      
      var l = new List<string> {"A", "C", "D"};
      
      d.RemoveAll(l);
      
      foreach (var kvp in d)
      {
          Console.WriteLine(kvp.Key + ": " + kvp.Value);
      }
      

      输出:

      A: 4
      C: 99
      D: 46
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-14
        • 2018-01-17
        • 1970-01-01
        • 1970-01-01
        • 2018-12-04
        • 2013-07-09
        相关资源
        最近更新 更多