从 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 04:38:00  来源:igfitidea点击:

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

c#.netlinqcollectionsdictionary

提问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);