When reviewing, I sometimes encounter this kind of loop:
i = begin
while ( i != end ) {
// ... do stuff
if ( i == end-1 (the one-but-last element)
I think you have it entirely nailed. Most people fall into the trap of including conditional branches in loops, when they could do them outside: which is simply faster.
For example:
if(items == null)
return null;
StringBuilder result = new StringBuilder();
if(items.Length != 0)
{
result.Append(items[0]); // Special case outside loop.
for(int i = 1; i < items.Length; i++) // Note: we start at element one.
{
result.Append(";");
result.Append(items[i]);
}
}
return result.ToString();
And the middle case you described is just plain nasty. Imagine if that code grows and needs to be refactored into different methods.
Unless you are parsing XML <grin> loops should be kept as simple and concise as possible.
I prefer to simply, exclude the element from the loop and give a spearate treatment outside the loop
For eg: Lets consider the case of EOF
i = begin
while ( i != end -1 ) {
// ... do stuff for element from begn to second last element
increment i
}
if(given_array(end -1) != ''){
// do stuff for the EOF element in the array
}
Another thing I hate to see is the for-case pattern:
for (i=0; i<5; i++)
{
switch(i)
{
case 0:
// something
break;
case 1:
// something else
break;
// etc...
}
}
I've seen this in real code.
Which one performs better?
If the number of items is very large then I would always loop once, especially if you are going to perform some operation on every item. The cost of evaluating the conditional is likely to be less than looping twice.
Oops, of course you are not looping twice... In which case two loops is preferable. However, I maintain that the primary consideration should be performance. There's no need to incur the conditional in the loop (N times) if you can partition the work by a simple manipulation of the loop bounds (once).
The special case should be done outside the loop if it is only to be performed once.
However, there may be an index or some other variable(s) that are just easier to keep inside the loop due to scoping. There may also be a contextual reason for keeping all the operations on the datastructure together inside the loop control structure, though I think that is a weak argument on its own.
@xtofl,
I agree with your concern.
Million times I encountered similar problem.
Either developer adds special handling for first or for last element.
In most cases it is worth to just loop from startIdx + 1 or to endIdx - 1 element or even split one long loop into multiple shorter loops.
In a very rare cases it's not possible to split loop.
In my opinion uncommon things should be handled outside of the loop whenever possible.