I often find myself doing the following index-counter messiness in a foreach loop to find out if I am on the first element or not. Is there a more elegant way to do this in C#, something along the lines of if(this.foreach.Pass == 1)
etc.?
int index = 0; foreach (var websitePage in websitePages) { if(index == 0) classAttributePart = " class=\"first\""; sb.AppendLine(String.Format("<li" + classAttributePart + ">" + "<a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title)); index++; }
That is because foreach is meant to iterate over a container, making sure each item is visited exactly once, without changing the container, to avoid nasty side effects.
Because forEach does not wait for each promise to resolve, all the prizes are awarded in parallel, not serial (one by one). So the loop actually finishes iterating before any of the prizes have finished being awarded!
Luckily, there are several ways to get an index variable with foreach : Declare an integer variable before the loop, and then increase that one inside the loop with each loop cycle. Create a tuple that returns both the element's value and its index. Or swap the foreach loop with the for loop.
A callback function is a simple function that defines the operation to be performed on a single element, and the forEach() method makes sure it will be performed on each element of an array. The forEach() method has a pretty straightforward syntax: forEach(callback(currentElement, index, arr), thisValue);
Another approach is to accept that the "ugly part" has to be implemented somewhere and provide an abstraction that hides the "ugly part" so that you don't have to repeat it in multiple places and can focus on the specific algorithm. This can be done using C# lambda expressions (or using C# 2.0 anonymous delegates if you're restricted to .NET 2.0):
void ForEachWithFirst<T>(IEnumerable<T> en, Action<T> firstRun, Action<T> nextRun) { bool first = true; foreach(var e in en) { if (first) { first = false; firstRun(e); } else nextRun(e); } }
Now you can use this reusable method to implement your algorithm like this:
ForEachWithFirst(websitePages, (wp => sb.AppendLine(String.Format("<li class=\"first\">" + "<a href=\"{0}\">{1}</a></li>", wp.GetFileName(), wp.Title))) (wp => sb.AppendLine(String.Format("<li>" + "<a href=\"{0}\">{1}</a></li>", wp.GetFileName(), wp.Title))) );
You could design the abstraction differently depending on the exact repeating pattern. The good thing is that - thanks to lambda expression - the structure of the abstraction is completely up to you.
Slightly less verbose:
string classAttributePart = " class=\"first\""; foreach (var websitePage in websitePages) { sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title)); classAttributePart = string.Empty; }
If you are using .NET 3.5 you could use the overload of Select that gives you the index and test that. Then you also wouldn't need the StringBuilder. Here's the code for that:
string[] s = websitePages.Select((websitePage, i) => String.Format("<li{0}><a href=\"{1}\">{2}</a></li>\n", i == 0 ? " class=\"first\"" : "", websitePage.GetFileName(), websitePage.Title)).ToArray(); string result = string.Join("", s);
It looks a bit more verbose, but that's mainly because I broke the very long line many shorter ones.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With