从 ac# 字典中删除与谓词匹配的多个项目的最佳方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/469202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to remove multiple items matching a predicate from a c# Dictionary?
提问by Brann
I need to remove multiple items from a Dictionary. A simple way to do that is as follows :
我需要从字典中删除多个项目。一个简单的方法如下:
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);
The reason why I can't directly Remove the items in the foreach block is that this would throw an Exception ("Collection was modified...")
之所以不能直接 Remove the items in the foreach block 是因为这会抛出异常(“Collection was modified...”)
I'd like to do the following :
我想做以下事情:
MyCollection.RemoveAll(x =>x.Member==foo)
But the Dictionary<> class doesn't expose a RemoveAll(Predicate<> Match) method, like the List<> Class does.
但是 Dictionary<> 类没有像 List<> 类那样公开 RemoveAll(Predicate<> Match) 方法。
What's the best way (both performance wise and elegant wise) to do that?
做到这一点的最佳方法是什么(性能明智和优雅明智)?
采纳答案by JaredPar
Here's an alternate way
这是另一种方式
foreach ( var s in MyCollection.Where(kv => kv.Value.Member == foo).ToList() ) {
MyCollection.Remove(s.Key);
}
Pushing the code into a list directly allows you to avoid the "removing while enumerating" problem. The .ToList()
will force the enumeration before the foreach really starts.
将代码直接推送到列表中可以避免“枚举时删除”问题。在.ToList()
将迫使枚举真正开始在foreach之前。
回答by Geoff
Can you just change your loop to use an index (i.e. FOR instead of FOREACH)? You'd have to loop backwards, of course, i.e. count-1 down to zero.
您可以更改循环以使用索引(即 FOR 而不是 FOREACH)吗?当然,您必须向后循环,即计数 1 到零。
回答by Darin Dimitrov
Instead of removing just do the inverse (create a new dictionary from the old one containing only the elements you are interested in) and let the garbage collector take care of the old dictionary:
而不是删除只是做相反的事情(从旧字典中创建一个只包含您感兴趣的元素的新字典)并让垃圾收集器处理旧字典:
var newDictionary = oldDictionary.Where(x => x.Value != foo);
回答by aku
you can create an 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);
回答by Amy B
Instead of removing, just do the inverse. Create a new dictionary from the old one containing only the elements you are interested in.
而不是删除,只需做相反的事情。从旧字典创建一个新字典,其中仅包含您感兴趣的元素。
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);
}
回答by Jerome
Modified version of Aku's extension method solution. Main difference is that it allows the predicate to use the dictionary key. A minor difference is that it extends IDictionary rather than Dictionary.
Aku的扩展方法解决方案的修改版。主要区别在于它允许谓词使用字典键。一个细微的区别是它扩展了 IDictionary 而不是 Dictionary。
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);