Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extension methods Dictionary<TKey,TValue>.RemoveAll? Is it possible?

I've been trying to write an extension method to mimic List.RemoveAll(Predicate).

So far I've got 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?

like image 705
Rob Stevenson-Leggett Avatar asked Mar 17 '09 14:03

Rob Stevenson-Leggett


People also ask

Is .NET Dictionary thread safe?

NET 4.0 and is available in the System. Collections. Concurrent namespace. It is thread-safe and internally uses locking.

What is TKey C#?

The Dictionary<TKey, TValue> Class in C# is a collection of Keys and Values. It is a generic collection class in the System. Collections. Generic namespace. The Dictionary <TKey, TValue> generic class provides a mapping from a set of keys to a set of values.

Are there dictionaries in C#?

In C#, Dictionary is a generic collection which is generally used to store key/value pairs. The working of Dictionary is quite similar to the non-generic hashtable. The advantage of Dictionary is, it is generic type. Dictionary is defined under System.


2 Answers

Your code will not work because you are passing the Dictionary class by value. This means the final assignment (dict = temp) will not be visible to a calling function. It is not legal in C# to pass extension method targets by ref or out (in VB it's legal to do ByRef).

Instead you will need to modify the Dictionary inline. 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

Swapped the order of Where and ToList to reduce the size of the allocated memory of the list. It will now only allocate a list for the items that are to be removed.

like image 188
JaredPar Avatar answered Nov 27 '22 02:11

JaredPar


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 remove is small relative to the dictionary size this will be faster (if the number removed is likely to be zero you can make this even faster by lazily creating the toRemove list as well.

This boils down to the same as Jared's updated answer but allows you to defer the creation of the removal list if you so desire. If this is not an issue (and you have no reason to break point part way through the process) then Jared's is cleaner and simpler.

like image 44
ShuggyCoUk Avatar answered Nov 27 '22 03:11

ShuggyCoUk