• 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.
  • Posts

    • They have a concept of a plan. How fitting.
    • As Total War turns 25, Creative Assembly is teasing a "new era" for the strategy franchise by Pulasthi Ariyasinghe Creative Assembly has now officially been making Total War games for 25 years. It was in June 2000 that the UK-based studio put forth Shogun: Total War for PC, with Electronic Arts publishing the ambitious project. With a quarter of a century now behind the series, the developer is now looking towards the "next era" of Total War. The studio will host its first-ever Total War showcase in December 2025, which is described as a "flagship video presentation unveiling what’s next for the franchise." Creative Assembly said that the showcase will have announcements for new games as well as content for existing titles, with developer commentary also happening regarding the future of the series. "We’re honoured and humbled to be one of the few video games that get the chance to celebrate such a huge milestone, and we want to thank colleagues past and present, as well as our fans for all the support," says Total War vice president Roger Collum. "2025 marks an exciting new era for the franchise as we reveal what’s next for Total War, and we can’t wait to celebrate throughout the year with everyone." Read an anniversary letter from Roger Collum regarding the studio's history, Total War beginnings, and more over here. Prior to the showcase, Creative Assembly will be hosting retrospective video interviews, developer livestreams, and more behind-the-scenes content regarding the series starting this August. There will also be multiplayer tournaments for fans, giveaways, Q&A sessions with developers, mod spotlights, and more events happening during this period. As the studio celebrates the occasion, a massive Total War historical games sale has just gone live on Steam. This has discounts of up to 75% across everything from the original Shogun: Total War to the latest entry, Total War: PHARAOH. The discounts will last until June 26.
    • ANY standard Windows PC, either desktop or laptop, can install the Copilot app, period, no NPU or Copilot+ certification required. I should know, I have it running on a 3770K (2011) Windows 11 PC and works perfectly fine. So, your laptop can definitely run it, too.
    • Just what the driving public does not need--still another very attractive and addictive distraction.
    • You think Musk fixed any of that? Wow.
  • Recent Achievements

    • One Month Later
      POR2GAL4EVER earned a badge
      One Month Later
    • One Year In
      Orpheus13 earned a badge
      One Year In
    • One Month Later
      Orpheus13 earned a badge
      One Month Later
    • Week One Done
      Orpheus13 earned a badge
      Week One Done
    • Week One Done
      serfegyed earned a badge
      Week One Done
  • Popular Contributors

    1. 1
      +primortal
      539
    2. 2
      ATLien_0
      258
    3. 3
      +FloatingFatMan
      179
    4. 4
      +Edouard
      163
    5. 5
      Xenon
      118
  • Tell a friend

    Love Neowin? Tell a friend!