Dictionary enumeration in C#

56,830

Solution 1

To enumerate a dictionary you either enumerate the values within it:

Dictionary<int, string> dic;

foreach(string s in dic.Values)
{
   Console.WriteLine(s);
}

or the KeyValuePairs

foreach(KeyValuePair<int, string> kvp in dic)
{
   Console.WriteLine("Key : " + kvp.Key.ToString() + ", Value : " + kvp.Value);
}

or the keys

foreach(int key in dic.Keys)
{
    Console.WriteLine(key.ToString());
}

If you wish to update the items within the dictionary you need to do so slightly differently, because you can't update the instance while enumerating. What you'll need to do is enumerate a different collection that isn't being updated, like so:

Dictionary<int, string> newValues = new Dictionary<int, string>() { 1, "Test" };
foreach(KeyValuePair<int, string> kvp in newValues)
{
   dic[kvp.Key] = kvp.Value; // will automatically add the item if it's not there
}

To remove items, do so in a similar way, enumerating the collection of items we want to remove rather than the dictionary itself.

List<int> keys = new List<int>() { 1, 3 };
foreach(int key in keys)
{
   dic.Remove(key);
}

Solution 2

In answer to the problem "I can't update value/key inside foreach()", you cannot modify a collection while enumerating it. I would approach this by making a copy of the Keys collection:

Dictionary<int,int> dic=new Dictionary<int, int>();

//...fill the dictionary

int[] keys = dic.Keys.ToArray();
foreach (int i in keys)
{
    dic.Remove(i);
}

Solution 3

Foreach. There are three ways: You can enumerate over the Keys property, over the Values property or over the dictionary itself which is an enumerator of KeyValuePair<TKey, TValue>.

Solution 4

I just answered the same (updated) question for lists, so here's the same thing for dictionaries.

public static void MutateEach(this IDictionary<TKey, TValue> dict, Func<TKey, TValue, KeyValuePair<TKey, TValue>> mutator)
{
    var removals = new List<TKey>();
    var additions = new List<KeyValuePair<TKey, TValue>>();

    foreach (var pair in dict)
    {
        var newPair = mutator(pair.Key, pair.Value);
        if ((newPair.Key != pair.Key) || (newPair.Value != pair.Value))
        {
            removals.Add(pair.Key);
            additions.Add(newPair);
        }
    }

    foreach (var removal in removals)
        dict.Remove(removal);

    foreach (var addition in additions)
        dict.Add(addition.Key, addition.Value);
}

Note that we have to do the updates outside the loop, so we aren't modifying the dictionary as we enumerate it. Also this detects clashes caused by making two keys the same - it will throw (due to the use of Add).

Example - make all keys lowercase and trim all values, with a Dictionary<string, string>:

myDict.MutateEach(key => key.ToLower(), value => value.Trim());

If the keys are not unique when made lowercase, this will throw.

Share:
56,830
Ravi
Author by

Ravi

Updated on July 09, 2022

Comments

  • Ravi
    Ravi almost 2 years

    How do I enumerate a dictionary?

    Suppose I use foreach() for dictionay enumeration. I can't update a key/value pair inside foreach(). So I want some other method.

  • strager
    strager about 15 years
    Or you can enumerate the keys.
  • strager
    strager about 15 years
    No need for .ToArray() AFAIK. .Keys returns an IEnumerable.
  • spender
    spender about 15 years
    sure, but if the dictionary is altered in the loop, what happens to that enumeration? it changes, surely?
  • Ian
    Ian about 15 years
    I wouldn't have thought so. The dic.Keys will return an IEnumerable<int> in this case, which will be all values. If you were to just use the IEnumerator<int> instead then this might be the case.
  • spender
    spender about 15 years
    changing the line: foreach(int i in keys) to foreach(int i in dic.keys) throws and InvalidOperationException, "Collection was modified; enumeration operation may not execute." Making a copy, as above does not fail in this way.
  • Wedge
    Wedge about 15 years
    I'd expect that enumerating the keys would be more common than enumerating only the values (at least it has been in my experience), since you can find the value for the key quite easily (that being the point of the dictionary).
  • Edyn
    Edyn over 12 years
    You can still do it inline, just add .ToArray()... so foreach(int i in dic.Keys.ToArray())
  • Edyn
    Edyn over 12 years
    This covers the enumeration but not the update. To update, you'll need to use one of the methods below... see spender's answer.
  • spender
    spender over 12 years
    Sure, you can do it inline, but it's the same thing at the end of the day. In the optimized release binary, it probably gets inlined anyway. On separate lines, it's easier to debug if something goes wrong.