从ac#Dictionary中删除与谓词匹配的多个项目的最佳方法?

Bra*_*ann 51 .net c# linq collections dictionary

我需要从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);
Run Code Online (Sandbox Code Playgroud)

我无法直接删除foreach块中的项目的原因是这会抛出异常("Collection was modified ...")

我想做以下事情:

 MyCollection.RemoveAll(x =>x.Member==foo)
Run Code Online (Sandbox Code Playgroud)

但是Dictionary <>类没有公开RemoveAll(Predicate <> Match)方法,就像List <> Class那样.

这样做的最佳方式(性能明智和优雅明智)是什么?

Jar*_*Par 86

这是另一种方式

foreach ( var s in MyCollection.Where(kv => kv.Value.Member == foo).ToList() ) {
  MyCollection.Remove(s.Key);
}
Run Code Online (Sandbox Code Playgroud)

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

  • @Jim,这里绝对需要.ToList.foreach主体修改底层集合.如果没有.ToList(),Where子句将针对修改后的集合进行操作.使用.ToList()强制查询在发生任何删除之前完成 (10认同)
  • ToArray() 会比 ToList() 更轻吗? (2认同)

aku*_*aku 21

你可以创建一个扩展方法:

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);
Run Code Online (Sandbox Code Playgroud)


Amy*_*y B 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);
}
Run Code Online (Sandbox Code Playgroud)


Jer*_*ome 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);
Run Code Online (Sandbox Code Playgroud)


The*_*ias 5

从 .NET 3.0 开始,现在允许从Dictionary<TKey,TValue>枚举它的同时删除项目。根据文档

仅限 .NET Core 3.0+:唯一不会使枚举器无效的变异方法是RemoveClear

以下是提议并批准此更改的 GitHub 问题:允许字典<K,V>.在枚举期间删除

所以RemoveAll扩展方法可以简单地实现如下:

/// <remarks>.NET Core 3.0+ only.</remarks>
public static void RemoveAll<TKey, TValue>(this Dictionary<TKey, TValue> source,
    Predicate<KeyValuePair<TKey, TValue>> predicate)
{
    foreach (var pair in source)
        if (predicate(pair))
            source.Remove(pair.Key);
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

myDictionary.RemoveAll(e => e.Value.Member == foo);
Run Code Online (Sandbox Code Playgroud)