2009-03-17 12 views
7

私は、List.RemoveAll(Predicate)を模倣する拡張メソッドを作成しようとしています。拡張メソッド辞書<TKey,TValue> .RemoveAll?出来ますか?

public static void RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict, 
            Predicate<KeyValuePair<TKey,TValue>> condition) 
{ 
    Dictionary<TKey,TValue> temp = new Dictionary<TKey,TValue>(); 

    foreach (var item in dict) 
    { 
     if (!condition.Invoke(item)) 
      temp.Add(item.Key, item.Value); 
    } 

    dict = temp; 
} 

任意のポインタ:

は、これまでのところ私はこれを持っていますか?これは完全に素朴な実装ですか?

+0

KeyValuePairの代わりにKeyだけで述語を一致させることで、辞書からペアを削除したくないですか? – base2

答えて

16

Dictionaryクラスを値渡ししているため、コードが機能しません。つまり、最後の代入(dict = temp)は呼び出し元の関数には表示されません。 C#では、拡張メソッドのターゲットをrefまたはoutで渡すことは正当ではありません(VBではByRefを実行するのが合法です)。

代わりにディクショナリのインラインを変更する必要があります。リストの割り当てられたメモリのサイズを小さくするためにどこで、ToListメソッドの順序をスワップ

public static void RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict, 
            Func<KeyValuePair<TKey,TValue>,bool> condition) 
{ 
    foreach (var cur in dict.Where(condition).ToList()) { 
     dict.Remove(cur.Key); 
    } 
} 

次EDIT

を試してみてください。これで、削除されるアイテムのリストだけが割り当てられます。削除数がゼロである可能性が高い場合には削除するキーの数は、辞書サイズに対して小さい場合

+0

毎回キーリストに十分なメモリを割り当てるという欠点があります。確かにシンプルです – ShuggyCoUk

+0

実際には動作しません... –

+0

@ロブどのように?私が使用したサンプルデータのためにうまく動作します – JaredPar

4
public static void RemoveAll<TKey,TValue>(
    this Dictionary<TKey,TValue> dict, 
    Predicate<KeyValuePair<TKey,TValue>> condition) 
{ 
    var toRemove = new List<TKey>(); 

    foreach (var item in dict) 
    { 
     if (!condition(item)) 
      toRemove.Add(item); 
    } 
    foreach (var key in toRemove) 
    { 
     dict.Remove(key); 
    } 
} 

これは速くなります(あなたも速く怠惰にもtoRemoveリストを作成することによって、これを行うことができます。

これは、Jaredの更新された回答と同じですが、必要に応じて削除リストの作成を延期することができます。これは問題ではない場合もあります)その後、Jared'sはよりクリーンでシンプルになります。

+0

条件のcondition.Invoke(...)メソッドを呼び出す必要はありません。デリゲート。あなたは単にconditionを直接呼び出すことができます。条件(アイテム)。 – base2

+0

@ base2私はオリジナルのユーザースタイルを複製していました。私はそれがInvokeなしで良いことに同意する、私はそれを変更します – ShuggyCoUk

1

"dict"パラメータがrefereによって渡されないため、このメソッドは機能しませんnceであり、refは拡張メソッドの最初のパラメータとしてサポートされていないため、実際は存在しません。

public static void RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict, 
           Predicate<KeyValuePair<TKey,TValue>> condition) 
{ 
    var temp = new List<TKey>(); 

    foreach (var item in dict) 
    { 
     if (!condition(item)) 
      temp.Add(item.Key); 
    } 

    foreach (var itemKey in temp) 
     dict.Remove(itemKey) 
} 

私はRemoveAllByKeyとRemoveAllByValueの実装も見たいと思います。

0

しかし、あなたが望むのであれば、新しい辞書を返すことができます。あなたの署名は、これに変更します

var newDict = oldDict.RemoveAll(kvp=> kvp.Name.StartsWith("something")); 

をそして、あなたはoldDictを変更したい場合、あなたはこのようにそれを呼び出します:

public static Dictionary<TKey, TValue> RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict, 
           Predicate<KeyValuePair<TKey,TValue>> condition) 

そして、呼び出し元のコードを言う

oldDict = oldDict.RemoveAll(kvp=> kvp.Name.StartsWith("something")); 
関連する問題