Learning From A Popular Interview Question
This is another post in the genre of technical interview questions I’ve come across during my job hunt, and how to go about solving them (For more posts see here, here, and here).
Today’s question is a simple one, but the correct answer gets to the basics of a very popular feature in most languages; so popular, we almost never give it any thought.
The question is the following: write a function that prints all the odd numbers up to 20.
Sounds simple, right? Any beginner will tell you that this is a job for a for
loop. So let’s write it out:
for(let i=0; i<=20; i++){
if(i%2===1){
console.log(i)
}
}
In (over)simplified English: we run a loop for 20 iterations, during each iteration of the loop we check to see if the value of a variable i
is odd and if it is we print it to the console.
The above function satisfies the requirements. If you run it in your console, you will see it does the job. The question is, is there a better way to do things?
What The For Loop?
Note: for more information about JavaScript for loops see the documentation on W3Schools
Obviously, there is (otherwise there would be no point to this blog post); to understand how, let’s take a closer look at the syntax of the for
loop, and more specifically, the first line:
for(let i=0; i<20; i++){
We can see that the for
loop takes as an argument three statements separated by ;
’s. Let’s take a closer look at them.
The first statement is an expression that is run only one time, before the for
loop gets executed. It’s usually used to initialize a counter, but you can put any valid JavaScript expression, or none at all (for example, if you already initialized your counter outside of the for loop). In the example above, the first statement defines a variable i
and sets its value to 0
.
The second statement is a conditional which gets evaluated before each iteration of the loop. As long as the conditional evaluates to true
the loop keeps running. Once conditions change so that the second statement evaluates to false
, we break out of the loop. In our example, the conditional is i < 20
so the loop runs as long as the value of i
remains below 20
.
The third statement is another expression. This expression is run after every iteration of the loop. It’s usually used to increment the counter, but again, you can put any legal JavaScript in there, and it will run (of course, if you aren’t using it to increment a counter you need to make sure you have another way of changing your conditional in the second statement to true, otherwise you will be stuck with a dreaded infinite loop).
In our previous example, we are using the third statement to increment the value of i
after each iteration, so that after 20 iterations i
is equal to 20
, i < 20
evaluates to true
, and we break out of the loop.
We Can Do Better
Now let’s take a look at our function and see how we can optimize it.
As a refresher here is the function:
for(let i=0; i<=20; i++){
if(i%2===1){
console.log(i)
}
}
So we set the value of i
to zero and start the loop. At each iteration of the loop we check the current value of i
, if it’s odd, we log it to the console, and then we increment i
by 1 and rerun the loop until i
hits 20 at which point we break the loop.
How can we optimize this?
The key is in the third statement. As mentioned earlier, nothing is forcing us to increment our counter by 1 in the third statement; we can do whatever we want. Combining that knowledge with the fact that 1 is an odd number, and that adding 2 to an odd number gives us an odd number as well and the result is a loop that only has to run half of the iterations our previous attempt used.
Try putting the following in your console and see how it runs the same:
for(let i=1; i<=20; i +=2 ){
console.log(i)
}
The differences between this function and the previous one is that here we set the initial value of i
to 1
and instead of incrementing i
by one for each iteration we increment it by two (we also got rid of the if
statement because we know that now i
is always odd, so we just log the value of i
each time without checking).
So we see how sometimes knowing how things work under the hood can help us when we want to tweak them beyond the way they are usually used.
I hope this post inspired you to sometimes delve a little deeper, even into concepts that “everyone knows”.
Happy coding!
This article has been cross-posted from my blog Rabbi On Rails.
You can read more about my coding journey there, or by following me on Twitter @yechielk