关于.NET:从C#字典中删除与谓词匹配的多个项的最佳方法?

Best way to remove multiple items matching a predicate from a c# Dictionary?

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

1
2
3
4
5
6
  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块中的项的原因是这会引发异常("集合已修改…")

我想做以下工作:

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

但是dictionary<>类不会像list<>类那样公开removeall(谓词<>匹配)方法。

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


这是另一种方法

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

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


可以创建扩展方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);


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

1
2
3
4
5
6
7
8
9
10
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);
}


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);


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


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

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