Unnecessary Loops

One thing that sometimes appears in code written by people with a limited knowledge of programming is the use of loops to perform processing where loops are not required. Less common is where recursion is used where a simple loop will do. In each case the person writing the code has written less than optimal code as a result of not fully comprehending the relationships between the data they are processing. This occurs more frequently with JavaScript than it does with other languages because there people using other languages are more likely to know more about programming. There are a lot of people using JavaScript who have learnt JavaScript but who have not learnt anything more than that about programming.

Since loops are the more commonly misused, we'll look at a common situation where loops are misused to examine how a little thought can do away with the need for a loop and hence reduce (perhaps significantly) the amount of time the code will take to run.

A really common situation where loops are used unnecessarily is with date processing. I have never come across a situation where a loop would be needed to perform date processing because the Date object built into JavaScript provides everything we need to be able to perform whatever date manipulations we like without needing loops.

Let's start with a simple example where we want to obtain the last date of the last Saturday in a given month. Now there are all sorts of different approaches that JavaScript beginners would take if they don't yet know enough JavaScript to realise how easy it is to get the last day of the month. Even those who know the simplest way to get the last day of the month will then proceed to use an unnecessary loop to get the last Saturday.

d = new Date(yr,mth,0);
while (d.getDay() !=6) {
d.setDate(d.getDate() -1);

Those with enough programming experience to know that loops are never needed for date processing will replace the loop with a single statement.

d = new Date(yr,mth,0);
d.setDate(d.getDate() - (d.getDay()+1)%7);

We are using exactly the same date methods to get the answer as with the loop but instead of subtracting the days one by one to get back to the last Saturday we work out how many days to subtract based on what day of the week the last day is on and subtract the whole amount in one go.

Now this isn't going to make any noticeable difference to the processing time in this instance since at most the loop will run six times but if we get into the habit of never using loops for date processing even in trivial situations like this then we will not use them in situations where they are significantly less efficient.

We don't need a loop to count the number of days between two dates. We can make use of our knowledge that the Date object records all the dates as the number of milliseconds from a given date to just subtract the one date from the other and then divide by the number of milliseconds in a day.

this.dayDiff = function(d) {return Math.floor(Math.abs(_this-d)/86400000);};

Suppose though that we want the number of business days between two dates. Imagine that the two dates are ten years apart. Now if we were to loop though every day in that period testing for the day of the week and incrementing a counter every time the day is not a Saturday or Sunday we'd need to loop about 3650 times. Of course the same pattern would be repeated every seven times through the loop resulting in five being added for every seven iterations. The only difference would be at the very start and the very end of the loop if either end date is not a business day. This again means that no loop is needed and simply by getting the number of days between the end dates via the simple subtraction and then testing for whether either end date is a Saturday or Sunday and adjusting accordingly we can obtain the number of business days between two dates a billion years apart without needing a loop.

this.busDayDiff = function(d2) {
var d = this.dayDiff(d2);
var t= d%7;
if (this < d2) {
w1= this.getDay();
w2= d2.getDay();
} else {
w2= this.getDay();
w1= d2.getDay();
if (w1 > w2) t-=2;
if ((w1 == 0 && w2 == 6) || w1 == 6) t--;
return Math.abs((Math.floor(d/7)*5)+t);

Now this code may be slightly harder to read than a loop that tests each day for what day of the week it is but this code runs exactly eight statements regardless of how many days there are between the two dates and so will take the same amount of time to run if the dates are a hundred years apart as it will if the dates are both in the same week.

The same logic can be applied to any situation involving dates to get rid of any loops in your processing. It can also be extended to anywhere else that you might consider using loops where there is a regular pattern to the data. Anywhere where a pattern to the data exists and where you are after a single answer there is no need for a loop. You can make use of the pattern to eliminate the need for a loop.

The only situation where a pattern exists and where you still need a loop is where the intention is to process each and every value and not just retrieve a single value. For example the only situation where a loop is required for date processing is where you are displaying a calendar and need loops to display the days and weeks.


This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow