user2455816
user2455816

Reputation: 51

How to access a nested Dictionary<> objects in a foreach loop

I have a nested Dictionary structure like this:

Dictionary<string, Dictionary<string, string>> dict;

I'm trying to access the elements using two foreach loops but the compiler won't let me use the following as the loop variable for my inner loop:

Dictionary<string, string>

This is what I have:

foreach (string key in dict.Keys) {
    foreach (Dictionary<string, string> innerDict in dict[key]) {
        // ...
    }
}

The compiler says:

Cannot convert type 'System.Collections.Generic.KeyValuePair<string,string>'
 to 'System.Collections.Generic.Dictionary<string,string>'

I can use KeyValuePair<string,string> in the inner loop, but I would like to access the dictionary object itself as a whole (so that I can do something like this: if (dict.ContainsKey(innerDict)) { ... })

Upvotes: 5

Views: 17537

Answers (7)

Kami
Kami

Reputation: 19407

I think you are misunderstanding the underlying Dictionary structure.

Dictionary<string, Dictionary<string, string>>

The above results in a parent containing a single dictionary object. When you attempt to use foreach over this object the compiler does not know what to do. It might be easier to understand if you use the following code

Dictionary<string,string> dictionaryObject;
foreach (string item in dictionaryObject)
{ }

The above will also result in the same error.

You can resolve your issue by iterating over the keys or values of the dictionary object, for example,

foreach (string  key in dict.Keys)
{
    foreach (string innerKey in dict[key].Keys)
    {
        System.Diagnostics.Debug.WriteLine(dict[key][innerKey]);
    }
}

Upvotes: 1

Matthew Watson
Matthew Watson

Reputation: 109567

The minimum code change to fix it is like this (but see the correct approach in the next code snippet in this answer):

Dictionary<string, Dictionary<string, string>> dict;

foreach (string key in dict.Keys)
{
    foreach (var innerDict in dict[key].Select(k => k.Value))
    {
    }
}

Your problem was that when you enumerate over a dictionary, you get a sequence of Key/Value pairs. In your case, the Value was the inner dictionary, and it is that which you needed.

I'm using the Linq "Select()" operation to convert each key/value pair into just the value part, i.e. the dictionary which is the value in the key/value pair.

However, that's a long-winded and inefficient way to go about getting each inner dictionary along with its key. Here's how it should be done:

foreach (var item in dict)
{
    string key = item.Key;
    Dictionary<string, string> innerDict = item.Value;

    // Do something with key and innerDict.
}

I'm assuming that you are trying to visit each inner dictionary in turn while knowning that inner dictionary's key in the outer dictionary.

Note that I only copied the values from item.Key and item.Value into local variables to illustrate their types. You could just use item.Key and item.Value directly, of course.

If you really only want the inner dictionaries themselves (and you don't need the key for each inner dictionary), you can just do it like so (as Nuffin suggested):

foreach (var innerDict in dict.Values)
{
    // Use inner dictionary
}

Upvotes: 5

Oliver
Oliver

Reputation: 45101

Should be not so hard:

Dictionary<string, Dictionary<string, string>> dict = new Dictionary<string,Dictionary<string,string>>();

foreach (var kvp in dict)
{
    var innerDict = kvp.Value;

    foreach (var innerKvp in innerDict)
    {
        Console.WriteLine(kvp.Key + " " + innerKvp.Key + " " + innerKvp.Value);
    }
}

Upvotes: 0

Geeky Guy
Geeky Guy

Reputation: 9399

You could just keep it short by using:

foreach (Dictionary<string, string> d in dict.Values) {
}

It works, no complaints from the compiler.

Also notice that your code doesn't work because in that context, dict[key] is not a collection of dictionaries, but a single dictionary.

Upvotes: 1

nvoigt
nvoigt

Reputation: 77304

foreach (Dictionary<string, string> innerDict in dict[key]) {
        // ...
    }

This fails because dict[key] is a Dictionary<string,string>, so enumerating it with foreach will yield elements of type KeyValuePair<string,string>.

If you want to access the inner dictionary, just do so and drop the foreach loop.

Dictionary<string, string> innerDict = dict[key];

Upvotes: 0

Bill Gregg
Bill Gregg

Reputation: 7147

You will still have the dictionary to reference just like you wish, even when you use the KVP. Try this:

foreach (var outerKVP in dict {
    foreach (var innerKVP in dict[outerKVP.Key]) {
        var theString = dict[outerKVP.Key][innerKVP.Key];
    }
}

Upvotes: 0

Mike Perrenoud
Mike Perrenoud

Reputation: 67898

That's because the value of the string key is not a list. Change the declaration of the Dictionary to Dictionary<string, List<Dictionary<string, string>>> dict; if that's what you want.

Or you could just grab the dictionary inside the first foreach loop like this:

Dictionary<string, string> val = dict[key];

and use it from there. But either way, you're trying to iterate against something that's not enumerable.

I think you may have the Dictionary defined like you want -you just don't need an inner loop.

Upvotes: 1

Related Questions