• 0

[C#] Assign values in dictionary


Question

Hi, I have say a

Dictionary<Color, int> myDict;

And I want to do this:

foreach (var kvPair in myDict) {
     kvPair.Value = 0; // not necessarily always 0, could be calculated per-value, whatever
}

But this triggers a compiler error:

Property or indexer 'System.Collections.Generic.KeyValuePair<Color,int>.Value' cannot be assigned to -- it is read only

How can I do this?

Link to comment
https://www.neowin.net/forum/topic/871176-c-assign-values-in-dictionary/
Share on other sites

14 answers to this question

Recommended Posts

  • 0

You can't alter a collection in a foreach loop, convert it to a normal for loop.

*Nevermind* that would be adding/removing the collection item...

for(int i=0; i< myDict.Values; i++)

{

kvPair....

}

  • 0
  On 01/02/2010 at 02:36, Calum said:

Does it work if you try the following?

foreach (KeyValuePair kvPair in myDict) {
     kvPair.Value = 0; // not necessarily always 0, could be calculated per-value, whatever
}

C# will infer System.Collections.Generic.KeyValuePair if you put var, so it's equivalent.

Actually I know of a way, but it's ugly and wastes CPU cycles:

foreach (Color color in Enum.GetValues(typeof(Color))) {
     myDict[color] = 0;
}

I'm wondering if I should use another container or if there's a more idiomatic way.

  • 0
  On 01/02/2010 at 02:41, Dr_Asik said:

C# will infer System.Collections.Generic.KeyValuePair if you put var, so it's equivalent.

Actually I know of a way, but it's ugly and wastes CPU cycles:

foreach (Color color in Enum.GetValues(typeof(Color))) {
     myDict[color] = 0;
}

I'm wondering if I should use another container or if there's a more idiomatic way.

Not using KVPs I don't think, since KVP objects are basically read-only once they have been instantiated for reasons which are beyond me (Why make the value member read-only?). I was going suggest using a SortedDictionary object since they're implemented as a binary tree and you could use a depth-first search to basically loop through the whole collection, but the OrderedDictionary object doesn't provide the facility to do it.

I was also going to suggest foreach'ing through the "Keys" collection, but I suspect that that would be less efficient than what you suggested.

I would say that it would be easier just to take the performance hit in this case, since the lookup time for a Dictionary is close to O(1) since its implemented as a hash table. Unless its a completely performance critical piece of code, in which case you might need to look into some of the other collection types.

  • 0

As previously stated, KeyValuePair<K, V> is a structure (read: not class) with read-only properties. The reasons behind this is that structures perform better when they are immutable. It's better to instantiate a new instance of a KeyValuePair<K, V> then to try and modify it's content. That being said, you can't modify an enumeration, this is also be design, so:

foreach (var pair in myDict) {
  pair.Value = 0; // This will fail because of read-only properties.
}

foreach (var pair in myDict) {
  pair = new KeyValuePair&lt;...&gt; // Won't work as you are modifying a read-only variable.
}

Whereas:

foreach (Color key in myDict.Keys) {
  myDict[key] = 0; // Make the modification here
}

... should work, as the you are enumerating over a collection of keys, not KeyValuePair<Color, int> items, and can modify the contents of the dictionary correctly.

  • Like 3
  • 0
  On 01/02/2010 at 09:18, Antaris said:

As previously stated, KeyValuePair<K, V> is a structure (read: not class) with read-only properties. The reasons behind this is that structures perform better when they are immutable.

And now I know! Thanks Antaris, have some Rep! :D

  • 0
  On 01/02/2010 at 09:18, Antaris said:

Whereas:

foreach (Color key in myDict.Keys) {
  myDict[key] = 0; // Make the modification here
}

... should work, as the you are enumerating over a collection of keys, not KeyValuePair<Color, int> items, and can modify the contents of the dictionary correctly.

Well, I'm afraid it doesn't, after testing it, I get a runtime error on the second iteration saying it cannot continue because the collection has been modified. So, back to iterating over Enum.GetValues for now. :unsure:
  • 0
  On 01/02/2010 at 18:28, Dr_Asik said:

Well, I'm afraid it doesn't, after testing it, I get a runtime error on the second iteration saying it cannot continue because the collection has been modified. So, back to iterating over Enum.GetValues for now. :unsure:

You get an error because the Keys collection is invalid after changing the value. Now, you can get around this by iterating over a list which temporarily holds the keys. That way, you get a List<Color> which contains all keys at that certain point. This list is not managed by the Dictionary and therefore won't be invalidated when you make changes to the Dictionary.

foreach (Color key in myDict.Keys.ToList()) {
    myDict[key] = 0; // Make the modification here
}

This appears to be the fastest and safest way to do this, so go and make good use of it. :)

  • 0
  On 01/02/2010 at 18:43, Calculator said:

foreach (Color key in myDict.Keys.ToList()) {
    myDict[key] = 0; // Make the modification here
}

This appears to be the fastest and safest way to do this, so go and make good use of it. :)

So are the keys cached in an array (or equivalent) then? I figured that it wouldn't be, whereas the enum values would just be known, making it less safe, but faster. Am I way off then?

  • 0
  On 01/02/2010 at 19:04, Majesticmerc said:

So are the keys cached in an array (or equivalent) then? I figured that it wouldn't be, whereas the enum values would just be known, making it less safe, but faster. Am I way off then?

Enum.GetValues() creates an array, while myDict.Keys.ToList() creates a List. Either way, allocation of a container every time. I don't like either, but it seems there's no other way.

It's a bit silly, but anyhow if I was writing for ideal performance I'd be using C++ so I guess it's tolerable.

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.