代码之家  ›  专栏  ›  技术社区  ›  Brann

从C字典中删除与谓词匹配的多个项的最佳方法?

  •  50
  • Brann  · 技术社区  · 16 年前

    我需要从字典中删除多个项目。 一个简单的方法如下:

      List<string> keystoremove= new List<string>();
      foreach (KeyValuePair<string,object> k in MyCollection)
         if (k.Value.Member==foo)
            keystoremove.Add(k.Key);
      foreach (string s in keystoremove)
            MyCollection.Remove(s);
    

    我无法直接删除foreach块中的项的原因是这将引发异常(“集合已修改…”)

    我想做以下工作:

     MyCollection.RemoveAll(x =>x.Member==foo)
    

    但是Dictionary类不会像List类那样公开removeall(谓词匹配)方法。

    最好的方法是什么(无论是性能方面还是优雅方面)?

    6 回复  |  直到 7 年前
        1
  •  80
  •   n00bmind JaredPar    10 年前

    这是另一种方法

    foreach ( var s in MyCollection.Where(kv => kv.Value.Member == foo).ToList() ) {
      MyCollection.Remove(s.Key);
    }
    

    直接将代码推到列表中可以避免“枚举时删除”问题。这个 .ToList() 将在foreach真正开始之前强制枚举。

        2
  •  21
  •   Community CDub    7 年前

    您可以创建一个 extension method :

    public static class DictionaryExtensions
    {
        public static void RemoveAll<TKey, TValue>(this IDictionary<TKey, TValue> dict, 
            Func<TValue, bool> predicate)
        {
            var keys = dict.Keys.Where(k => predicate(dict[k])).ToList();
            foreach (var key in keys)
            {
                dict.Remove(key);
            }
        }
    }
    
    ...
    
    dictionary.RemoveAll(x => x.Member == foo);
    
        3
  •  11
  •   Amy B    16 年前

    不要移除,只要做相反的操作。从旧词典创建一个新词典,只包含您感兴趣的元素。

    public Dictionary<T, U> NewDictionaryFiltered<T, U>
    (
      Dictionary<T, U> source,
      Func<T, U, bool> filter
    )
    {
    return source
      .Where(x => filter(x.Key, x.Value))
      .ToDictionary(x => x.Key, x => x.Value);
    }
    
        4
  •  10
  •   wimh    11 年前

    AKU扩展方法解决方案的修改版本。主要区别在于它允许谓词使用字典键。一个微小的区别是它扩展了IDictionary而不是字典。

    public static class DictionaryExtensions
    {
        public static void RemoveAll<TKey, TValue>(this IDictionary<TKey, TValue> dic,
            Func<TKey, TValue, bool> predicate)
        {
            var keys = dic.Keys.Where(k => predicate(k, dic[k])).ToList();
            foreach (var key in keys)
            {
                dic.Remove(key);
            }
        }
    }
    
    . . .
    
    dictionary.RemoveAll((k,v) => v.Member == foo);
    
        5
  •  0
  •   Geoff    16 年前

    你能改变你的循环使用一个索引吗(也就是说,for而不是foreach)?当然,您必须向后循环,也就是说,将count-1向下循环为零。

        6
  •  -1
  •   Ian Kemp    8 年前

    不要删除,而是执行相反的操作(从只包含您感兴趣元素的旧字典中创建一个新字典),让垃圾收集器处理旧字典:

    var newDictionary = oldDictionary.Where(x => x.Value != foo);