Why is the condition with the highest or lowest values often placed first in similar cases?

In a number of flow control lessons involving this kind of solution, the provided solutions have often begun with the conditions having the greatest values, like so…

MAIN SOLUTION


// As a function declaration:
function lifePhase (age) {
    if (age < 0 || age > 140) {
       return 'This is not a valid age'
   } else if (age < 4) {
        return 'baby'
    } else if (age < 13) {
        return 'child'
    } else if (age < 20) {
       return 'teen'
    } else if (age < 65) {
       return 'adult'
    } else {
        return 'senior citizen'
    }  
}
console.log(lifePhase(5)) 

However, the code below was my own solution.

What is the reason behind this solution or testing the condition with the highest value first against the one below?

May I get a solid explanation for why the procedure in the provided solution?

Thanks

MY SOLUTION

// Write your function here:
function lifePhase (age){
  if (age > 0 || age <= 3){
    return "baby";
  } else if (age >= 4 || age <= 12){
    return "child";
  } else if (age >= 13 || age <= 19){
    return "teen";
  } else if (age >= 20 || age <= 64){
    return "adult";
  } else if (age >= 65 || age <= 140){
    return "senior citizen";
  } else if (age < 0 || age > 140){
    return "This is not a valid age";
  }
}

console.log(lifePhase(14));



https://www.codecademy.com/paths/web-development/tracks/getting-started-with-javascript/modules/code-challenge-javascript-fundamentals/lessons/javascript-fundamentals-code-challenge/exercises/life-phase

Efficiency, in a word.

If the condition which tests for invalid values is the first one in your if-else branching structure, then you can quickly determine that either:

  • the user provided a valid entry which should be assessed, or
  • the user provided an invalid entry, and we should ignore it

If it’s invalid, you know immediately and can go back to the user with the appropriate notification without wasting CPU cycles. If it’s valid, the value proceeds through the rest of the branching structure and is evaluated appropriately.

If the test for an invalid value is last, as in your solution, we waste computing cycles by testing an invalid entry against the expected cases before eventually arriving at the conclusion that the provided value was invalid.

Think of it like the line for a rollercoaster; the “you must be this tall to ride” signage is usually at the entrance to join the line, so you don’t waste your time waiting only to get to the front and find out you’re not tall enough. It’s the same principle.

2 Likes

Wow! awesome.

Your explanation is very appreciated and the principle behind testing the invalid value first, understood.

Now can we discuss the technicalities behind the method applied in the main solution as against my solution?

Specifically, why the usage of ONLY “less than” sign as against my usage of both “less than equal to” and “greater than equal to” signs?

I know my approach made my code cumbersome which is a good reason to use a cleaner approach. But what is the explanation behind the main approach?

Sorry, I missed this bit.

You don’t need the lower bounds, because previous branches are “filtering out” inapplicable cases.

The first if removes any invalid ages, i.e. those not between 0 and 140. If the value is “valid”, we don’t run the code block for the if and we move on to else if...

JavaScript proceeds successively through the branches until it matches a condition, so if age = 15, for example, we do the following tests:

age = 15

age < 0 OR age > 140 : FALSE, move on.
age < 4 : FALSE, move on.
age < 13 : FALSE, move on.
age < 20 : TRUE! Return "teen".

As you’ve tested for, and excluded, the lower bound value with previous branches we can just specify the upper bound as in the solution. :slight_smile:

Does that make sense?

A bit more clarification will do here. :smile:

As in you need me to explain it a bit differently, or you now understand it? :slight_smile:

Yes, kindly explain it a bit differently.

Right…

You should, by this stage, understand how the if-else conditional structure works in JavaScript, but to be on the safe side (and for the benefit of future viewers of this topic) let’s recap.

Let’s consider a basic if-else structure, with some pseudo-code elements to make things a bit easier.

if (some condition) {
    run this code;
} else if (some other condition) { 
   run this code instead;
} else {
    run this code if all else fails;
}

The first thing that JavaScript will examine in this conditional is the if line. JavaScript will look at the condition, or conditions, that you have given it and decide whether they have been met. If they have, the condition is true and we run the code inside the “if-block” (run this code;).

If, however, JavaScript decides that the condition is not met - the if condition is false - then we move on down the structure. In the case of our example, we move to the else if.

JavaScript does the same thing again, examining the condition to see if it has been met. If it has, we run the code inside the “else-if-block” (run this code instead;). If that condition isn’t met, then we move on to the else.

The else block is your “last resort” - this code will only ever be run if none of the conditions above it are met. Hence why in my pseudo-code example, the “else-block” is run this code if all else fails;.


Let’s apply this knowledge to the example solution from the Codecademy lesson. Here’s the code again, if you need a refresher:

Click me for the code
// As a function declaration:
function lifePhase (age) {
    if (age < 0 || age > 140) {
       return 'This is not a valid age'
   } else if (age < 4) {
        return 'baby'
    } else if (age < 13) {
        return 'child'
    } else if (age < 20) {
       return 'teen'
    } else if (age < 65) {
       return 'adult'
    } else {
        return 'senior citizen'
    }  
}
console.log(lifePhase(15)) 

Like before, I will be using age = 15.

The first part of the conditional which we evaluate is the if:

  1. if (age < 0 || age > 140) {
       return "This is not a valid age";
    }
    

This condition is used to weed out invalid inputs. We know someone can’t have a negative age, which is why we are testing for age < 0, and an age of over 140 years is highly unlikely so we also test for age > 140. If we meet either of these conditions, then we would return the message “This is not a valid age”. We’ve set age = 15, remember, so this condition evaluates to false. JavaScript does not run this block, and instead moves on to the next condition.

  1. else if (age < 4) {
       return "baby";
    }
    

This condition checks to see if age < 4, and if so returns the message “baby”. Again, remember that we are using age = 15, so this condition is also false. JavaScript will now move on to the next conditional, but let’s recap what we now know about the value for age:

  • The if branch proved that age is between 0 - 140, because we checked to see if it was outside of that range. We didn’t run that code, so we know 0 <= age <= 140.
  • The first else if branch proved that age is greater than or equal to 4, because we checked to see if it was less than 4. So, we now know that 4 <= age <= 140.
  1. else if (age < 13) {
       return "child";
    }
    

This condition is checking to see if age < 13, and if it is we will return the message “child”. Once again, since age = 15, we don’t meet this condition either so this code block does not run. We move on to the next condition, knowing that:

  • The if branch proved that age is between 0 and 140,
  • The first else if branch proved that age is greater than or equal to 4, so is in the range of 4 - 140, and
  • The second else if branch has just proved that age is greater than or equal to 13, so we now know that it’s somewhere in the range of 13 - 140.
  1. else if (age < 20) {
       return "teen";
    }
    

This condition is checking to see if age < 20, which it is because age = 15. This condition is the first one which is true, and so we execute this code block and return the message “teen”.

Hopefully, by now, you can see that each condition in the series is narrowing the range of possible values for age.

If you have tested to see if age is below a certain threshold, for example age < 4, and that code doesn’t run then you know that the value of age must be at least 4. Being able to infer this logically is why we don’t need to specify age >= 4 in the condition; we already know that because a previous test ruled it out.

Does that make it any clearer? :slight_smile: