Reputation: 51
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
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
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
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
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
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
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
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