2

I am trying to search through a dictionary to see if it has a certain value and if so then to change it. Here is my code:

foreach (var d in dictionary)
{
    if (d.Value == "red")
    {
         d.Value = "blue";
    }
}

In visual studio when i step through the code debugging it i can see it change the value then when it hits the foreach loop to reiterate again it throws an exception

"Collection was modified; enumeration operation may not execute"

How do i fix this?

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
brian4342
  • 1,265
  • 8
  • 33
  • 69

6 Answers6

6

You can't change it in the middle of the foreach - you'll need to come up with some other mechanism, such as:

// Get the KeyValuePair items to change in a separate collection (list)
var pairsToChange = dictionary.Where(d => d.Value == "red").ToList();
foreach(var kvp in pairsToChange)
    dictionary[kvp.Key] = "blue";
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • This works in the simple case, as was asked here. If, however, there is more involved than a simple value check this won't work as well. Is there a reason you prefer this method, which involves potentially doubling memory usage to one such as I suggested (iterating over the keys)? – Jeff Mar 20 '13 at 15:37
  • @mattytommo It's a `List>` - kvp will be a KeyValuePair, and have a Key property. This is because `Dictionary` is `IEnumerable>` - http://msdn.microsoft.com/en-us/library/xfhwa508.aspx – Reed Copsey Mar 20 '13 at 15:40
  • @Jeff Your solution actually gives the exact same error - you can't change the dictionary while enumerating keys... – Reed Copsey Mar 20 '13 at 15:43
1

If you want to replace all occurences of "red", you'll need to store the KeyValuePairs in a list or something like that:

var redEntries = dictionary.Where(e => e.Value == "red").ToList();
foreach (var entry in redEntries) {
    dictionary[entry.Key] = "blue";
}
Botz3000
  • 39,020
  • 8
  • 103
  • 127
1

You can't modify a collection whilst you're enumerating over it (in a loop).

You'll need to add your changes to a collection, then change them separately. Something like:

var itemsToChange = dictionary
    .Where(d => d.Value == "red")
    .ToDictionary(d => d.Key, d => d.Value);

foreach (var item in itemsToChange)
{
    dictionary[item.Key] = "blue";
}
Mathew Thompson
  • 55,877
  • 15
  • 127
  • 148
  • This works - but making a dictionary here is quite a bit more expensive than a `List>` – Reed Copsey Mar 20 '13 at 15:45
  • @ReedCopsey Exactly *how* expensive? They both have *some* overhead, but I'd bet the difference in cost was small. – Mathew Thompson Mar 20 '13 at 15:55
  • If I recall correctly, a dictionary has 5 extra managed allocations on the heap, plus you're going to create classes for the closures required to loop and extract the key and the value, etc. Probably doesn't matter for most things, but it's quite a bit more complicated than a simple list. You're right in that, in most cases, it's probably not noticeable at all, but it is a more complex. – Reed Copsey Mar 20 '13 at 15:59
1
var dict = new Dictionary<string, string>()
          {
                  { "first", "green" },
                  { "second", "red" },
                  { "third", "blue" }
          };

foreach (var key in dict.Keys.ToArray())
{
    if (dict[key] == "red")
    {
        dict[key] = "blue";
    }
}
Y.Yanavichus
  • 2,387
  • 1
  • 21
  • 34
0

You cannot modify the collection you are iterating over in a foreach loop. If you could do that, it would open up several problems, such as "Do I run it on this newly-added value too?"

Instead, you should do something like this:

foreach( string key in dictionary.Keys )
{
    if( dictionary[key] == "red" )
    {
        dictionary[key] = "blue";
    }
}
Jeff
  • 2,835
  • 3
  • 41
  • 69
0

Objects in foreach loops are read-only.

Please read through this and this for more understanding.

Community
  • 1
  • 1
Yahya
  • 3,386
  • 3
  • 22
  • 40
  • This is true, but spectacularly unhelpful. You've told him what the problem is, but have given no clue as to how to fix it. – Jeff Mar 20 '13 at 15:38
  • @Jeff Correct Jeff, should have posted solution too. Pasted those two links to help Brian understand underlying mechanism. – Yahya Mar 20 '13 at 15:43