[C#] Dictionary Loop

I’ve just found out that using a foreach loop is bad (an extra GC alloc).
I’ve got to do a loop on a dictionary on each update and currently using a foreach.
I’ve found out that there is another way to do a loop on dictionary using for with elementAt by using System.Linq.

the questions are:

  • Why is it bad to use for + elementAt for dictionary loop?
  • Can System.Linq be used by Net 2.0 subset?
  • Is there any other way to do a dictionary loop without foreach?

Still learning C#, Thank you.

is that extra gc going to completely break your game? if not it’s really not worth worrying about it until you get towards the end of the project when you start optimising things.

1 Like

It’s true but I hate to do major restructuring on multiple class later if I could avoid it by early optimizing.
Oh, by the way, I’m working on a mobile game.

Linq has the same problems as foreach on Unity’s mono compiler, as far as I am aware.

The foreach isn’t that bad, and since Dictionary doesn’t have any indexed way to acces it’s members, Linq has to use the same enumerator internally as foreach does.

Linq can be nice but a lot of times there is no gain over using it since it is basically going to do the same thing as a foreach in this case anyway. I try to use Linq when it improves readability and/or reduces nesting significantly.

Why would you need to use elementAt in a loop? If you intend to actually loop through the dictionary then you would loop through all of the elements so the elementAt is pointless.

foreach(var key in someDictionary.Keys) // loop through keys
foreach(var value in someDictionary.Values) // loop through values
foreach(KeyValuePair<K, V> p in someDictionary) // loop through both
7 Likes

I thought something like this

for (int i = 0; i < n; ++i) {
    // do something with dictionary.ElementAt(i)
}

Oh my…
So there are no other way?

I guess you could implement your own Dictionary, where you have direct access to the key/value pairs, but I can guarantee that you won’t be able to have it run as fast as the built-in one, as that’s well optimized by a bunch of people.

I’d rather use the foreach, but you can do something like

        Dictionary<string, string> dict = new Dictionary<string, string>()
        {
            { "A", "String A" },
            { "B", "String B" },
            { "C", "String C" },
        };
        string[] keys = new string[dict.Keys.Count];
        dict.Keys.CopyTo(keys, 0);
        for (int i = 0; i < keys.Length; ++i)
        {
            Debug.Log(dict[keys [i]]);
        }

If you don’t change the keys that often, you could just update the keys array whenever you update the dictionary.

1 Like

Why do this when you could iterate through the part of the kvp you want like the code I posted?

I think a KeyedCollection might also work.

no. Doesnt solve anything.

OrderedDictionary is what you want, however last I checked (which was pre-unity5) OrderedDictionary wasnt available.

might pay to check if it is now, although im doubtful.

I’ve checked on 5, I could use OrderedDictionary by using System.Collections.Specialized.
By “wasn’t available” did you mean it won’t work on Net 2.0 Subset (after I build it on iOS)?

Sorry, I should’ve mentioned that I currently am using foreach and wanted to know is there any other way to do dictionary loop without extra GC alloc.

Hmm, what about this one?
Any drawback?

The drawback is the CopyTo, which can be expensive. If you can cache the array, or your dictionary isn’t that large you’ll probably be OK.

This is the on proper way I know, no memory allocation, fast and simple enough.
You could make enumerator typed but its type is so complicated, I guess we can forget it this one time

var enumerator = my_dictionary.GetEnumerator();
while( enumerator.MoveNext() )
{
    // Access value with enumerator.Current.Value;
}
1 Like

I didn’t know about GetEnumerator + MoveNext method before you pointed one.
I’ve done some research and found that GetEnumerator is better than foreach in here http://www.dotnetperls.com/dictionary-getenumerator

Then I’ve done a little profiling with both method and found out that yes the GetEnumerator method didn’t give an extra GC alloc.

Thanks :slight_smile:

2 Likes

How are you using your dictionary? Do you actually need to loop through its entirety each frame?

At worst case yes.
For multitouch handling without the new UI system.

Could you describe an example, maybe post some code in context?

I’m really sorry, but it’s like a super spaghetti code.
Currently I’m doing some cleaning up and restructuring, so maybe I’ll post it when it’s clean.

Unfortunately your first line of code:

var enumerator = my_dictionary.GetEnumerator();

still creates garbage. And since you need to call it every time the Dictionary size changes, you can’t get a GC-free Dictionary…