views:

122

answers:

3

I have a dictionary collection as bleow:

mydic.addvalue(key1, val1)
mydic.addvalue(key2, val1)
mydic.addvalue(key3, val1)
mydic.addvalue(key4, val2)
mydic.addvalue(key5, val2)

From the above dictionary I want to delete all the entries where value == "val1", so that the result would have only following entry:

mydic.addvalue(key4, val2)
mydic.addvalue(key5, val2)

My VB source code is on VS2008 and targeted for 3.5

+6  A: 

You first need to find all keys for which the associated value is val1:

var keysToRemove = mydic.Where(kvp => kvp.Value == val1)
                        .Select(kvp => kvp.Key)
                        .ToArray();

Then you can remove each of those keys:

foreach (var key in keysToRemove)
{
    mydic.Remove(key);
}
dtb
This. But (@user) keep in mind that you'll need to do extra work for equality if the TValue is a reference type (unless you're fine just comparing references, that is). Also the `.ToArray()` or `.ToList()` is absolutely necessary in order to iterate over the results in a foreach *and* modify the original dictionary.
Anthony Pegram
Thank you for quick response. I know this may sound silly, but what is kvp? since I have never worked on linQ
@user, in this case, it is merely shorthand for KeyValuePar. But the name itself is unimportant in this context, it could be *anything*. Look into lambdas, but the short short version is that in `(kvp => kvp.Value == val1)`, `kvp` is the name of the supplied argument (in this case a KeyValuePair), and `kvp.Value == val1` is the expression that evaluates to true or false. This is because a LINQ Where clause uses a function that takes in a typed parameter and returns a bool.
Anthony Pegram
Thank you for the clarification. Can this be done without using LinQ?
@user, I'll post a non-LINQ answer.
Anthony Pegram
+2  A: 

You can also use

var x= (from k in mydic
           where k.Value != val1
           select k).ToDictionary(k=>k.key);

x will not have any of the val1's

RandomNoob
But it will also be a new dictionary. Any references to the original dictionary would now be useless unless they are uninterested in keys/values that have been removed (or added, altered, etc.).
Anthony Pegram
shoot, you are correct.
RandomNoob
Better solution would be the first one var keys = (from d in mydic where d.Value == "val1" select d.Key).ToList(); foreach (string key in keys) { mydic.Remove(key); }
RandomNoob
+2  A: 

A non-LINQ answer based on a comment by the user.

private static void RemoveByValue<TKey,TValue>(Dictionary<TKey, TValue> dictionary, TValue someValue)
{
    List<TKey> itemsToRemove = new List<TKey>();

    foreach (var pair in dictionary)
    {
        if (pair.Value.Equals(someValue))
            itemsToRemove.Add(pair.Key);
    }

    foreach (TKey item in itemsToRemove)
    {
        dictionary.Remove(item);
    }
}

Example usage:

Dictionary<int, string> dictionary = new Dictionary<int, string>();
dictionary.Add(1, "foo");
dictionary.Add(2, "foo");
dictionary.Add(3, "bar");
string someValue = "foo";
RemoveByValue(dictionary, someValue);

Same caveat as with the other answers: if your value determines equality by reference, you'll need to do extra work. This is just a base.

Anthony Pegram