我需要从Dictionary中删除多个项目。 一种简单的方法如下:
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块中的项目的原因是这会抛出异常(“Collection was modified ...”)
我想做以下事情:
MyCollection.RemoveAll(x =>x.Member==foo)
但字典&lt;&gt; class不公开RemoveAll(Predicate&lt;&gt; Match)方法,例如List&lt;&gt;上课。
这样做的最佳方式(性能明智和优雅明智)是什么?
答案 0 :(得分:82)
这是另一种方式
foreach ( var s in MyCollection.Where(kv => kv.Value.Member == foo).ToList() ) {
MyCollection.Remove(s.Key);
}
直接将代码推送到列表中可以避免“在枚举时删除”问题。 .ToList()
将在foreach真正开始之前强制枚举。
答案 1 :(得分:21)
您可以创建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);
答案 2 :(得分:11)
不是删除,而是反过来。从旧的字典中创建一个只包含您感兴趣的元素的字典。
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);
}
答案 3 :(得分:10)
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);
答案 4 :(得分:0)
你能改变循环使用索引(即FOR而不是FOREACH)吗?当然,你必须向后循环,即将count-1降为零。
答案 5 :(得分:0)
最快的删除方式是:
public static void RemoveAll<TKey, TValue>(this IDictionary<TKey, TValue> idict, Func<KeyValuePair<TKey, TValue>, bool> predicate)
{
foreach (var kvp in idict.Where(predicate).ToList())
{
idict.Remove(kvp.Key);
}
}
或
public static void RemoveAll<T>(this ICollection<T> icollection, Predicate<T> predicate)
{
var nonMatchingItems = new List<T>();
// Move all the items that do not match to another collection.
foreach (var item in icollection)
{
if (!predicate(item))
{
nonMatchingItems.Add(item);
}
}
// Clear the collection and then copy back the non-matched items.
icollection.Clear();
foreach (var item in nonMatchingItems)
{
icollection.Add(item);
}
}
取决于您是否还有更多谓词返回true的情况。两者本质上都是O(N),但是如果“删除/查找”的情况很少,则第一种方法会更快,而如果集合中的项目大多数时候都符合条件,则第二种方法会更快。
答案 6 :(得分:-1)
而不是只删除反向(从只包含你感兴趣的元素的旧字典创建一个新字典),让垃圾收集器处理旧字典:
var newDictionary = oldDictionary.Where(x => x.Value != foo);
答案 7 :(得分:-1)
使用 LINQ 很简单。只需执行以下操作:)
MyCollection = MyCollection.Where(mc => !keystoremove.Contains(mc.Key))
.ToDictionary(d => d.Key, d => d.Value);