The same key for four calls?
Or how not to do loops.
I cannot use a for loop here obviously because if I do so, say for example I start the loop from 1, then the value for the first run of the loop will be 1 and it will pick up the first key throughout these four calls of the function which I do not want. I want to get 1 in the first call of the functions, get second value in the second call and so on.
Don't put the four calls in the loop.
If you do either this:
var keys = new List<string>(dict.Keys);
for (var index = 0; index < keys.Count; index++)
{
myFunction(dict[keys[index]]);
myFunction(dict[keys[index]]);
myFunction(dict[keys[index]]);
myFunction(dict[keys[index]]);
}
Or this:
var values = new List<string>(dict.Values);
for (var index = 0; index < values.Count; index++)
{
myFunction(values[index]);
myFunction(values[index]);
myFunction(values[index]);
myFunction(values[index]);
}
Or this:
foreach (var key in dict.Keys)
{
myFunction(dict[key]);
myFunction(dict[key]);
myFunction(dict[key]);
myFunction(dict[key]);
}
Or this:
foreach (var pair in dict)
{
myFunction(pair.Value);
myFunction(pair.Value);
myFunction(pair.Value);
myFunction(pair.Value);
}
Or this:
foreach (var value in dict.Values)
{
myFunction(value);
myFunction(value);
myFunction(value);
myFunction(value);
}
You will get hte function myFunction
being called with the same value four times, for each value.
How to do for or foreach loops
Instead, put a single call in the loop. Remember that the loop is used to repeat something, so by placing it in the loop it will be repeated.
So do this:
var keys = new List<string>(dict.Keys);
for (var index = 0; index < keys.Count; index++)
{
myFunction(dict[keys[index]]);
}
So do this:
var values = new List<string>(dict.Values);
for (var index = 0; index < values.Count; index++)
{
myFunction(values[index]);
}
Or this:
foreach (var key in dict.Keys)
{
myFunction(dict[key]);
}
Or this:
foreach (var pair in dict)
{
myFunction(pair.Value);
}
Or this:
foreach (var value in dict.Values)
{
myFunction(value);
}
You may also do this:
var keys = new List<string>(dict.Keys);
keys.ForEach(key => myFunction(dict[key]));
Or this:
var values = new List<string>(dict.Values);
values.ForEach(value => myFunction(value));
Or if you prefer to throw some Linq in the mix (which I presume, since you added the Linq
tag), you can do this:
dict.Keys.ToList().ForEach(key => myFunction(dict[key]));
This also works:
dict.Values.ToList().ForEach(value => myFunction(value));
How to do while loops
Let's say that you don't want to do a for or foreach loop at all. Well, lets see...
A for loop like this one:
var keys = new List<string>(dict.Keys);
for (var index = 0; index < keys.Count; index++)
{
myFunction(dict[keys[index]]);
}
Can be done like this:
var keys = new List<string>(dict.Keys);
var index = 0;
while (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
And a foreach loop like this one:
foreach (var key in dict.Keys)
{
myFunction(dict[key]);
}
Can be done like this:
var enumerator = dict.Keys.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var key = enumerator.Current;
myFunction(dict[key]);
}
}
finally
{
enumerator.Dispose();
}
Of course, you can also do it like this:
var enumerator = dict.Values.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var value = enumerator.Current;
myFunction(value);
}
}
finally
{
enumerator.Dispose();
}
Or like this:
var enumerator = dict.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var pair = enumerator.Current;
myFunction(pair.Value);
}
}
finally
{
enumerator.Dispose();
}
This transformation is similar to the one the compiler does internally. By doing this, you may have more flexibility in some situations... yet, it is also more error prone.
How to not do loop
Let's pretend that you don't want to loop at all. This is possible if you know at compile time what is the number of elements. We can get there by unrolling a for, such as the while
we had before:
var keys = new List<string>(dict.Keys);
var index = 0;
while (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
Turn the while
into an if
and repeat it. The result looks like this:
var keys = new List<string>(dict.Keys);
var index = 0;
if (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
if (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
if (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
if (index < keys.Count)
{
myFunction(dict[keys[index]]);
index++
}
Well, if know the value of index
and the number of items in the dictionary, we know when index < keys.Count
is true. So we can remove those if
statements and repelace them with their inner code (since they are true). We end up with this:
var keys = new List<string>(dict.Keys);
var index = 0;
myFunction(dict[keys[index]]);
index = 1;
myFunction(dict[keys[index]]);
index = 2;
myFunction(dict[keys[index]]);
index = 3;
myFunction(dict[keys[index]]);
index = 4;
Finally, we inline the index variable:
var keys = new List<string>(dict.Keys);
myFunction(dict[keys[0]]);
myFunction(dict[keys[1]]);
myFunction(dict[keys[2]]);
myFunction(dict[keys[3]]);
Ta-Da! no loop.
Of course, you can also do it like this:
var values = new List<string>(dict.Values);
myFunction(values[0]);
myFunction(values[1]);
myFunction(values[2]);
myFunction(values[3]);