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); } |
直接将代码推到列表中可以避免"枚举时删除"问题。
可以创建扩展方法:
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); |