Reputation:
How do I iterate over a Dictionary's keys while maintaining the index of the key.
What I've done is merge a foreach
-loop with a local variable i
which gets incremented by one for every round of the loop.
Here's my code that works:
public IterateOverMyDict()
{
int i=-1;
foreach (string key in myDict.Keys)
{
i++;
Console.Write(i.ToString() + " : " + key);
}
}
However, it seems really low tech to use a local variable i
.
I was wondering if there's a way where I don't have to use the "extra" variable?
Not saying this is a bad way, but is there a better one?
Upvotes: 13
Views: 39326
Reputation: 1097
The Select((Entry, Index) => new { Entry, Index }) approach is probably best in the specific context of this question but, as an alternative, System.Linq.Enumerable now lets you convert a dictionary into a list. Something like this would work:
var x = dictionary.ToList();
for (int y=0; y<x.Count; y++) Console.WriteLine(y + " = " + x[y].Key);
There are pros & cons to both approaches depending on what you're trying to do.
Upvotes: -1
Reputation: 2310
Dictionaries are not exactly lists, arrays, or vectors. They take those constructs a step further. The key can be the index:
Dictionary myDictionary<int, string> = new Dictionary<int, string>()
{
{0, "cat"},
{1, "dog"},
{2, "pig"},
{3, "horse"}
};
myDictionary[4] = "hat";
for int i = 0; i <5; i++){
Console.Writeline(myDictionary[i]);
}
At this point you are probably missing most of the benefits of a dictionary (which is similar to enumeration with the benefit of sorting quickly on key values), and using it like a list.
Upvotes: 0
Reputation: 1503629
There's no such concept as "the index of the key". You should always treat a Dictionary<TKey, TValue>
as having an unpredictable order - where the order which you happen to get when iterating over it may change. (So in theory, you could add one new entry, and the entries could be in a completely different order next time you iterated over them. In theory this could even happen without you changing the data, but that's less likely in normal implementations.)
If you really want to get the numeric index which you happened to observe this time, you could use:
foreach (var x in dictionary.Select((Entry, Index) => new { Entry, Index }))
{
Console.WriteLine("{0}: {1} = {2}", x.Index, x.Entry.Key, x.Entry.Value);
}
... but be aware that that's a fairly misleading display, as it suggests an inherent ordering.
From the documentation:
For purposes of enumeration, each item in the dictionary is treated as a
KeyValuePair<TKey, TValue>
structure representing a value and its key. The order in which the items are returned is undefined.
EDIT: If you don't like the Select
call here, you could create your own extension method:
public struct IndexedValue<T>
{
private readonly T value;
private readonly int index;
public T Value { get { return value; } }
public int Index { get { return index; } }
public IndexedValue(T value, int index)
{
this.value = value;
this.index = index;
}
}
public static class Extensions
{
public static IEnumerable<IndexedValue<T>> WithIndex<T>
(this IEnumerable<T> source)
{
return source.Select((value, index) => new IndexedValue<T>(value, index));
}
}
Then your loop would be:
foreach (var x in dictionary.WithIndex())
{
Console.WriteLine("{0}: {1} = {2}", x.Index, x.Value.Key, x.Value.Value);
}
Upvotes: 29
Reputation: 203819
Not really. Note that keys in a dictionary are not logically "ordered". They don't have an index. There is no first or last key, from the Dictionary's point of view. You can keep track on your own whether this is the first key returned by the enumerator, as you are doing, but the Dictionary has no concept of "give me the 5th key", so you couldn't use a for
loop with an indexer as you could with a list or array.
Upvotes: 1
Reputation: 245489
Technically, the key is the index in a Dictionary<TKey, TValue>
. You're not guaranteed to get the items in any specific order, so there's really no numeric index to be applied.
Upvotes: 3