0

How would I go about in deleting a specified key within a Dictionary based on the following condition?

foreach (var kvp in dict)
            {
                if (kvp.Key.Contains('/'))
                {
                    //delete the key
                }
            }
Nolonar
  • 5,962
  • 3
  • 36
  • 55
Arianule
  • 8,811
  • 45
  • 116
  • 174

6 Answers6

9

You would do it like this:

foreach(var keyToDelete in dict.Keys.Where(x => x.Contains('/')).ToList())
    dict.Remove(keyToDelete);

The important thing here is the call to ToList() after the Where. This will put all keys that should be deleted into a new list which you can iterate.
If you would try this code without the ToList() you would get an InvalidOperationException:

Collection was modified; enumeration operation may not execute.

Please note that this code is more efficient than the currently accepted answer. It only copies the keys that need to be deleted instead of the complete dictionary.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • `ToArray` might have a bit less overhead than `ToList`, unless the OP is going to do anything with the items other than iterate over them once later on. – O. R. Mapper Feb 13 '13 at 08:19
  • @O.R.Mapper: "Might have" or "has"? :) Any references for this? – Daniel Hilgarth Feb 13 '13 at 08:20
  • Actually, "has", at least [a small amount](http://stackoverflow.com/questions/1508215/c-sharp-listdouble-size-vs-double-size) (that remains small if we assume that `Capacity` is not set to anything unreasonable). – O. R. Mapper Feb 13 '13 at 08:28
  • @O.R.Mapper: Thanks for the link. The difference is so marginal that I will continue using `ToList()` :) – Daniel Hilgarth Feb 13 '13 at 08:31
3

The problem is the fact that you can't modify a collection while looping over its elements. The solution is to put the keys to remove in a different collection and then looping over this to remove the elements. This is what Daniel's answer does.

If you can't/don't want to use LINQ, you can do it this way:

List<YourKeyType> toRemove = new List<YourKeyType>();
foreach (var kvp in dict)
{
    if (kvp.Key.Contains('/'))
        toRemove.Add(kvp.Key);
}
foreach (var aKey in toRemove)
    dict.Remove(aKey);
Francesco Baruchelli
  • 7,320
  • 2
  • 32
  • 40
  • Yours and Daniel Hilgarth's answers are by far the most efficient answer for removing multiple keys. Frankly, I find all the answers that involve making copies of the dictionary quite disturbing. – Matthew Watson Feb 13 '13 at 08:40
2

Depending on your data set, it might be more efficient to create a new object without the keys you want to discard:

dict = dict.Where(kvp => !kvp.Key.Contains('/'))
           .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

I could also argue that this is preferred to deleting keys since it communicates the intent of the code more clearly, but that is closely related to my personal coding style so your mileage may vary.

Christoffer
  • 12,712
  • 7
  • 37
  • 53
2

I realise this is already marked as answered, but I think that if you only want to delete a single key from a dictionary where the maximum size is not specified, making a copy of the ENTIRE dictionary just to remove one key is NOT a good solution!

To remove just one entry for a matching key, you can just do this:

foreach (var kvp in dict)
{
    if (kvp.Key.Contains('/'))
    {
        dict.Remove(kvp.Key);
        break;
    }
}

No copies of entire dictionaries required!

Note that this assumes there's only one key to be removed. If there might be more, use Daniel's or Francesco's answers above.

(Actually, I'll recommend you just use Daniel's answer, but I'll leave this here as an example without using Linq.)

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
1

EDIT: As said by the other answers below, what is important in the below code is calling ToList(). This will create a copy of dict which you will be able to iterate over while removing the items from dict without changing the collection you are iterating over.

You could do this by using something like

    dict.ToList().ForEach(a => { if (a.Key.Contains('/') dict.Remove(a.Key); });
Ash
  • 369
  • 1
  • 2
  • 13
  • 1
    For future visitors, it may be helpful to not just have some copy-and-paste code, but also an explanation of how this solves the question. – O. R. Mapper Feb 13 '13 at 08:29
  • 2
    I would have thought that making a copy of an entire dictionary just to remove one item from it is suboptimal... I suggest avoiding this and using Daniel Hilgarth's answer below (or mine if you only want to remove a single item). – Matthew Watson Feb 13 '13 at 08:38
  • 1
    @MatthewWatson: Indeed, Daniel's solution below is probably better in this respect. – O. R. Mapper Feb 13 '13 at 08:41
-2

Foreach will probably throw an exception. Try using for instead.

For deletion, use the Remove method.

petko_stankoski
  • 10,459
  • 41
  • 127
  • 231