Extension methods Dictionary <TKey, TValue> .RemoveAll? Is it possible?
I am trying to write an extension method to simulate List.RemoveAll (Predicate).
So far I have this:
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; } Any pointers? Is this a completely naive implementation?
Your code will not work because you are passing a Dictionary class by value. This means that the final assignment (dict = temp) will not be displayed to the calling function. In C #, it is not allowed to pass the goals of an extension method using ref or out (in VB, ByRef is legal to do this).
Instead, you will need to change the dictionary in the line. Try the following
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
Changed the order of Where and ToList to reduce the size of the allocated list memory. Now it will highlight the list only for items that need to be removed.
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); } } If the number of keys to delete is small relative to the size of the dictionary, this will be faster (if the number of deleted keys is likely to be zero, you can do it even faster by lazily creating a toRemove list.
It comes down to the same thing as Jared, but allows you to defer the creation of the deletion list if you wish. If this is not a problem (and you have no reason to interrupt the process of a partial part of the process), then Jared is cleaner and simpler.
This method will not work because the "dict" parameter is not passed by reference, and in fact it cannot be because ref is not supported as the first parameter of the extension method.
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) } I would also like to see implementations of RemoveAllByKey and RemoveAllByValue.
But if you wanted, you could return a new and different Dictionary. Your signature will change to this:
public static Dictionary<TKey, TValue> RemoveAll<TKey,TValue>(this Dictionary<TKey,TValue> dict, Predicate<KeyValuePair<TKey,TValue>> condition) And the calling code would say:
var newDict = oldDict.RemoveAll(kvp=> kvp.Name.StartsWith("something")); And if you want to change oldDict, you would call it the following:
oldDict = oldDict.RemoveAll(kvp=> kvp.Name.StartsWith("something"));