Foreach loops, part 2
This is part 2 out of a 2-part series on foreach loops. Click here for part 1.
Last time, we played around with foreach loops, and ended up deconstructing the loop into an iterative while loop. For fun and for profit- and for superior performance in the Unity engine! Today though, we’re going a little deeper.
But first, let’s take a look a the code we ended with last week and see where we can improve:
int iterationCount = 0;
while(iterationCount < collection.Length) {
var element = collection[iterationCount];
// the body of the foreach loop
iterationCount ++;
}
First things first – I’m going to cache the length of the array (or the count of a list or what have-you). I’ll explain why later.
int length = collection.Length;
while(iterationCount < length) {
…
Under the hood, part 2
Last week I explained that a CPU does not know what a foreach loop, -or a while or for loop, for that matter- is. You see, the code ultimately boils down to a compare and a branch instruction. And if statement and a jump– but in a loop, essentially. If you have no idea what I’m talking about, read the TIS-100 Reference Manual by Zach Barth first, and you’ll be able to follow along for the next bit.
Simply put, most processors use a zero-based design while comparing integers. So in our while loop, where we compare iterationCount and length, some math is performed to make one of the sides 0, like so:
iterationCount < length = iterationCount – length < 0
So in addition to a comparison and a branch we’re also doing an addition and a subtraction, for every iteration of the loop.
Reversing the loop
Sometimes you need to think outside of the box to fix these kinds of problems. As it turns out, we don’t need the iterationCount variable in the first place. Instead, we count down using the array’s length we cached earlier.
Int length = collection.Length;
while(length > 0) {
length –;
var element = collection[length];
// the body of the foreach loop
}
Now only one problem remains: what to do with the first iteration, where the length will be bigger than we can access in the array. That’s easilly solved by moving the post-decrement operator into the while statement.
int length = collection.Length;
while(length– > 0) {
var element = collection[length];
// the body of the foreach loop
}
Conclusion
This alternative to foreach loops has served me well. In most cases the order in which you process array elements actually doesn’t matter. In some situations, say, checking if items can be stacked in inventory code, order does matter. In that case you can either choose to reverse the order of the array, or you can just use a front-to-back approach. While either option works just fine, you’d probably be best off using the later option in most situations. As always, I hope you learned something, and I wish you a great coding week!