web-dev-qa-db-ja.com

述語に一致する複数のアイテムをC#辞書から削除する最良の方法?

辞書から複数のアイテムを削除する必要があります。これを行う簡単な方法は次のとおりです。

  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ブロックの項目を直接削除できないのは、これにより例外がスローされるためです(「コレクションが変更されました...」)。

私は次のようにしたいと思います:

 MyCollection.RemoveAll(x =>x.Member==foo)

ただし、Dictionary <>クラスは、List <>クラスのように、RemoveAll(Predicate <> Match)メソッドを公開しません。

それを行うための最良の方法は何ですか(パフォーマンスとエレガントの両方で)。

51
Brann

これが別の方法です

_foreach ( var s in MyCollection.Where(kv => kv.Value.Member == foo).ToList() ) {
  MyCollection.Remove(s.Key);
}
_

コードをリストに直接プッシュすると、「列挙中に削除」の問題を回避できます。 .ToList()は、foreachが実際に開始する前に列挙を強制します。

85
JaredPar

拡張メソッド を作成できます:

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);
21
aku

削除するのではなく、逆を行うだけです。興味のある要素のみを含む古い辞書から新しい辞書を作成します。

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);
}
11
Amy B

Akuの拡張メソッドソリューションの修正バージョン。主な違いは、述語が辞書キーを使用できることです。小さな違いは、辞書ではなくIDictionaryを拡張することです。

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);
10
Jerome

インデックスを使用するようにループを変更できますか(例:FOREACHではなくFOR)。もちろん、逆方向にループする必要があります。つまり、count-1をゼロに下げます。

0
Geoff

削除する代わりに、逆の操作を行い(関心のある要素のみを含む古い辞書から新しい辞書を作成)、ガベージコレクターに古い辞書を処理させます。

var newDictionary = oldDictionary.Where(x => x.Value != foo);
0
Darin Dimitrov