Temperature Converter with conditionals

Hi there, dear community!

I’ve decided to come to a halt as I was trying to finish the last step of the Mini Linter Project Project (since I was kind of overwhelmed by it) to trace back my steps to the very beginning of the course and do some random practice in the way.

I then came back to the Temperature Converter (Kelvin Weather) Project from the introduction unit and I started playing around with it to see if I’d properly grasps some of the concepts one sees in the following units.

This was my first attempt:

// Temperature Converter 1

const todaysTemperatureInKelvin = 293;

console.log(`Today is ${todaysTemperatureInKelvin} degrees Kelvin.`); // Returns "Today is 293 degrees Kelvin."

function convertToCelsius (todaysTemperatureInKelvin) {
   return todaysTemperatureInKelvin - 273;
}

console.log(`Today is ${convertToCelsius(todaysTemperatureInKelvin)} degrees Celsius.`); // Returns "Today is 20 degrees Celsius."

let todaysTemperatureInCelsius = convertToCelsius(todaysTemperatureInKelvin);

function convertToFahrenheit (todaysTemperatureInCelsius) {
   return todaysTemperatureInCelsius * (9/5) + 32;
} 

let todaysTemperatureInFahrenheit = convertToFahrenheit(todaysTemperatureInCelsius);
todaysTemperatureInFahrenheit = Math.floor(todaysTemperatureInFahrenheit);

console.log(`Today is ${todaysTemperatureInFahrenheit} degrees Fahrenheit.`); // Returns "Today is 68 degrees Fahrenheit."

Out of it, I achieved three proper results and I was kinda happy with them. These results were:

  1. Today is 293 degrees Kelvin.
  2. Today is 20 degrees Celsius.
  3. Today is 68 degrees Fahrenheit.

(Yep, in this case I forgot about Newton degrees.)

Thus, my second attempt (introducing Newton degrees and arrow functions):

// Temperature converter 2

const KelvinTemp = 293;

console.log(`Today is ${KelvinTemp} degrees Kelvin.`); // Returns «Today is 293 degrees Kelvin.»

let CelsiusTemp = (KelvinTemp) => {
    return KelvinTemp - 273;
}

console.log(`Today is ${CelsiusTemp(KelvinTemp)} degrees Celsisus.`); // Returns "Today is 20 degrees Celsius."

let FahrenheitTemp = (CelsiusTemp) => {
    return Math.floor(CelsiusTemp * (9/5) + 32);
}

console.log(`Today is ${FahrenheitTemp(CelsiusTemp(KelvinTemp))} degrees Fahrenheit.`); // Returns "Today is 68 degrees Fahrenheit."

let NewtonTemp = (CelsiusTemp) => {
    return Math.floor(CelsiusTemp * (33/100));
}

console.log(`Today is ${NewtonTemp(CelsiusTemp(KelvinTemp))} degrees Newton.`); // Returns "Today is 6 Newton."

So far, so good. Then, my third attempt: to compile it all in just one function, such as:


const kelvin = 293
function tempConverter (kelvin) {
    let celsius = kelvin - 273;
    let fahrenheit = Math.floor(celsius * (9/5) + 32);
    let newton = Math.floor(celsius * (33/100));
    return `${kelvin} degrees Kelvin is ${celsius} degrees Celsius, ${fahrenheit} degrees Fahrenheit and ${newton} degress Newton.`;
}

console.log(tempConverter(293));

And the thing also worked. Great!

Then, I tried mixing a few more concepts… and it was when apocalypse kinda overcame. At first, I was happy with this:

let temperature;
let degrees = ['Kelvin', 'Celsius', 'Fahrenheit', 'Newton'];
let kelvin;
let celsius;
let fahrenheit;
let newton

let tempConverter = (temperature, degrees) => {
    switch (degrees) {
        case 'Kelvin':
        kelvin = temperature;
        celsius = kelvin - 273;
        fahrenheit = Math.floor(celsius * (9/5) + 32);
        newton = Math.floor(celsius * (33/100));
        return `${kelvin} degrees Kelvin is ${celsius} degrees Celsius, ${fahrenheit} degrees Fahrenheit and ${newton} degrees Newton.`;
        break;
        case 'Celsius':
        celsius = temperature;
        kelvin = celsius + 273;
        fahrenheit = Math.floor(celsius * (9/5) + 32);
        newton = Math.floor(celsius * (33/100));
        return `${celsius} degrees Celsius is ${kelvin} degrees Kelvin, ${fahrenheit} degrees Fahrenheit and ${newton} degrees Newton.`;
        break;
        case 'Fahrenheit':
        fahrenheit = temperature;
        celsius = Math.floor((fahrenheit - 32) * 5/9);
        kelvin = celsius + 273;
        newton = Math.floor(celsius * (33/100));
        return `${fahrenheit} degrees Fahrenheit is ${celsius} degrees Celsius, ${kelvin} degrees Kelvin and ${newton} degrees Newton.`;
        break;
        case 'Newton':
        newton = temperature;
        celsius = Math.floor(newton / 0.3);
        kelvin = celsius + 273;
        fahrenheit = Math.floor(celsius * (9/5) + 32);
        return `${newton} degrees Newton is ${celsius} degrees Celsius, ${kelvin} degrees Kelvin and ${fahrenheit} degrees Fahrenheit.`;
        default:
        return 'Choose the proper degrees.';
}
}

As I logged the following, it all printed proper results:

console.log(tempConverter(293,'Kelvin')); // Returns "293 degrees Kelvin is 20 degrees Celsius, 68 degrees Fahrenheit and 6 degrees Newton."

console.log(tempConverter(20,'Celsius')); // Returns "20 degrees Celsius is 293 degrees Kelvin, 68 degrees Fahrenheit and 6 degrees Newton."

console.log(tempConverter(68,'Fahrenheit')); // Returns "68 degrees Fahrenheit is 20 degrees Celsius, 293 degrees Kelvin and 6 degrees Newton."

console.log(tempConverter(6,'Newton')); // Returns "6 degrees Newton is 20 degrees Celsius, 293 degrees Kelvin and 68 degrees Fahrenheit."

But I realized that

console.log(tempConverter('a','Newton'));
console.log(tempConverter(22, 'Ohyeah'));
console.log(tempConverter('Ohyeah', 'Ohyeah'));

returned inappropriate results. Respectively:

  1. a degrees Newton is NaN degrees Celsius, NaN degrees Kelvin and NaN degress Fahrenheit. — at ​​​console.log(tempConverter('a', 'Newton'));​​​
  2. Choose the proper degrees. — at console.log(​​​tempConverter(22, 'Ohyeah'));
  3. Choose the proper degrees. — at ​​console.log(​tempConverter('Ohyeah', 'Ohyeah'));

And so, I decided that I wanted to go ahead and try some validation processes. Which is why i wrote:

let temperature;
let degrees = ['Kelvin', 'Celsius', 'Fahrenheit', 'Newton'];
let kelvin;
let celsius;
let fahrenheit;
let newton

let tempConverter = (temperature, degrees) => {
    if (typeof temperature != 'number') {
        if (degrees != 'Kelvin' || degrees != 'Celsius' || degrees != 'Fahrenheit' || degrees != 'Newton') {
        return 'Temperature is not a number and you should choose a proper name for degrees.'
        } else if (typeof temperature === 'number') {
            switch (degrees) {
                case 'Kelvin':
                kelvin = temperature;
                celsius = kelvin - 273;
                fahrenheit = Math.floor(celsius * (9/5) + 32);
                newton = Math.floor(celsius * (33/100));
                return `${kelvin} degrees Kelvin is ${celsius} degrees Celsius, ${fahrenheit} degrees Fahrenheit and ${newton} degress Newton.`;
                break;
                case 'Celsius':
                celsius = temperature;
                kelvin = celsius + 273;
                fahrenheit = Math.floor(celsius * (9/5) + 32);
                newton = Math.floor(celsius * (33/100));
                return `${celsius} degrees Celsius is ${kelvin} degrees Kelvin, ${fahrenheit} degrees Fahrenheit and ${newton} degress Newton.`;
                break;
                case 'Fahrenheit':
                fahrenheit = temperature;
                celsius = Math.floor((fahrenheit - 32) * 5/9);
                kelvin = celsius + 273;
                newton = Math.floor(celsius * (33/100));
                return `${fahrenheit} degrees Fahrenheit is ${celsius} degrees Celsius, ${kelvin} degrees Kelvin and ${newton} degress Newton.`;
                break;
                case 'Newton':
                newton = temperature;
                celsius = Math.floor(newton / 0.3);
                kelvin = celsius + 273;
                fahrenheit = Math.floor(celsius * (9/5) + 32);
                return `${newton} degrees Newton is ${celsius} degrees Celsius, ${kelvin} degrees Kelvin and ${fahrenheit} degress Fahrenheit.`;
                default:
                return 'Choose the proper degrees.';
}
}
}
}

But the results were so discouraging:

  1. undefined ​​​​ ​at ​​​console.log(tempConverter(293, 'Kelvin'));
  2. undefined ​​​​​at ​​​console.log(tempConverter(20, 'Celsius'));
  3. undefined ​​​​​at ​​​console.log(tempConverter(68, 'Fahrenheit'));
  4. undefined ​​​​​at ​​​console.log(tempConverter(6, 'Newton'));
  5. Temperature is not a number and you should choose a proper name for degrees. — at ​​​console.log(tempConverter('a', 'Newton'));
  6. undefined ​​​​​at ​​​console.log(tempConverter(22, 'Ohyeah'));
  7. Temperature is not a number and you should choose a proper name for degrees. — at ​​​console.log(tempConverter('Ohyeah', 'Ohyeah'));

24 hours later, if I try to go over the code or to even write the validation process all over again, I end up writing the very same things, so something is quite missing in my reasoning process, but… what exactly? :sob:

Anyways, thanks for those who got to read this far and even more thanks to those of you guys who can help me out of this one :partying_face:

Cheers!

Hello,

i think temporarily adding some logging to your function will help a lot with the debug process. You’d be able to compare the logging you add to the output you’re already getting to draw some conclusions. One good spot would be after if conditions just to be sure you’re reaching the blocks of code you expect.

in this case, if you add a log after your first if where you’re checking if temperature is not a number and another one after where you check if temperature is a number (before your switch statement), you’ll find that whenever you send it a valid number, you never reach the switch statement. Right now you have your else if for the temperature being a number nested inside the code that only runs when the temperature is not a number. it’s basically unreachable code.

Your code to validate the degrees can’t work right now because you’re using or || instead of and && . Example, if degrees is Kelvin, then degrees !== 'Kelvin' is false, but degrees !== 'Celsius' is true. Since you used or ||, then it not being Celsius means if condition is met.

I hope this helps. I’m trying not to be too vague that it isn’t helpful, but also not trying to provide all the fixes or change the style so you can work on it and learn. Feel free to let me know if you need more details

1 Like

Dear @selectall,

first of all, let me thank you deeply once again for taking the time that reading my post implied.

Secondly, I am really happy to let you know that your words made find enlightenment, for I believe I’ve solved the puzzle.

This would be it:

let temperature;
let degrees = ['Kelvin','Celsius','Fahrenheit', 'Newton'];
let kelvin;
let celsius;
let fahrenheit;
let newton;

const tempConv = (temperature, degree) => {
    if (typeof temperature === 'number') {
        if (degree === degrees[0] || degree === degrees[1] || degree === degrees[2] || degree === degrees[3]) {
        switch (degree) {
            case degrees[0]:
                kelvin = temperature;
                celsius = temperature - 273;
                fahrenheit = Math.floor(celsius * (9/5) + 32);
                newton = Math.floor(celsius * (33/100));
                return `${kelvin} in degrees Kelvin is ${celsius} in degrees Celsius, ${fahrenheit} in Fahrenheit, and ${newton} in Newton.`;
                break;
            case degrees[1]:
                celsius = temperature;
                kelvin = celsius + 273;
                fahrenheit = Math.floor(celsius * (9/5) + 32);
                newton = Math.floor(celsius * (33/100));
                return `${celsius} in degrees Celsius is ${kelvin} in degrees Kelvin, ${fahrenheit} in Fahrenheit, and ${newton} in Newton.`;
                break;
            case degrees[2]:
                fahrenheit = temperature;
                celsius = Math.floor((fahrenheit - 32) * 5/9);
                kelvin = celsius + 273;
                newton = Math.floor(celsius * (33/100));
                return `${fahrenheit} in degrees Fahrenheit is ${celsius} in degrees Celsius, ${kelvin} in Kelvin, and ${newton} in Newton.`;
                break;
            case degrees[3]:
                newton = temperature;
                celsius = Math.floor(newton / 0.3);
                kelvin = celsius + 273;
                fahrenheit = Math.floor(celsius * (9/5) + 32);
                return `${newton} in degrees Newton is ${celsius} in degrees Celsius, ${kelvin} in Kelvin, and ${fahrenheit} in Fahrenheit.`;
                break;
        }
    }   else if (degree != degrees[0] || degree != degrees[1] || degree != degrees[2] || degree != degrees[3]) { 
        return 'Temperature is correct, but degree name is not.';
    }
} else if (typeof number != 'number') {
    if (degree === degrees[0] || degree === degrees[1] || degree === degrees[2] || degree === degrees[2]) {
        return 'Number is not a number, although the degree name is correct.'
    } else if (degree != degrees[0] || degree != degrees[1] || degree != degrees[2]) {
        return 'Number is not a number and the degree name is not correct.'
    }
}
}

console.log(tempConv(293, degrees[0]));
console.log(tempConv(20, degrees[1]));
console.log(tempConv(68, degrees[2]));
console.log(tempConv(6, degrees[3]));
console.log(tempConv(2, 'ernesto'));
console.log(tempConv('a', degrees[1]));
console.log(tempConv('a', degrees[5]));

Now, respectively, it finely returns as it follows:

  1. 293 in degrees Kelvin is 20 in degrees Celsius, 68 in Fahrenheit, and 6 in Newton.
  2. 20 in degrees Celsius is 293 in degrees Kelvin, 68 in Fahrenheit, and 6 in Newton.
  3. 68 in degrees Fahrenheit is 20 in degrees Celsius, 293 in Kelvin, and 6 in Newton.
  4. 6 in degrees Newton is 20 in degrees Celsius, 293 in Kelvin, and 68 in Fahrenheit.
  5. Temperature is correct, but degree name is not.
  6. Number is not a number, although the degree name is correct.
  7. Number is not a number and the degree name is not correct.

Realizing that I was searching for a specific degree when trying to validate each one of them cases — and not different degrees, so to speak — put me on a new way to discovery.

The fun thing here is that, in order to realize what I did realize, I had to go back one more step and simplify things a bit more, so I played a silly game with numbers and letters so that I could put aside what wasn’t so important at the moment (this is, working out the temperature conversion in itself):

let number;
let letters = ['a','b','c'];

const validation = (number, letter) => {
    if (typeof number === 'number') {
        if (letter === letters[0] || letter === letters[1] || letter === letters[2]) {
        return number + letter;
    } else if (letter != letters[0] || letter != letters[1] || letter != letters[2]) {
        return 'Number is correct but letters are not.';
    }
} else if (typeof number != 'number') {
    if (letter === letters[0] || letter === letters[1] || letter === letters[2]) {
        return 'Number is not a number, although letter is a letter.'
    }
}
}

console.log(validation(1,'a'));
console.log(validation(1,'b'));
console.log(validation(1,'c'));
console.log(validation(1,'d'));
console.log(validation('a','a'));

Now, first of all, I will keep in mind your advise about adding some logging to my functions to help with the debugging process. Secondly, my only follow-up question would be… am I still doing wrongly by using || in both of the cases I’ve just shown?

Thanks again! :heart:

Cheers!

You’re welcome. I’m happy that it was helpful and you were able to tackle the issues.

Yes and no. One you’re using perfectly, but the other you aren’t (though it doesn’t matter because you get the same output you’re after). Here is what I mean:

The one that works

(letter === letters[0] || letter === letters[1] || letter === letters[2])

Is going to have the effect you want. Let’s say that the letter is ‘c’. The logic becomes:

(false || false || true)

Since you used or || this condition is met because the final evaluation is true. You wanted this block to run if the letter was contained in your array, so it works perfectly.

The one that doesn’t work

(letter != letters[0] || letter != letters[1] || letter != letters[2])

Let’s use the letter value of ‘c’ again.

(true || true || false)

Because you used or ||, this condition is met because at least one of the values is true. You didn’t want this block to run if a value was true though. JavaScript won’t even look at the other conditions once it finds the first true because you used or ||

Alternative
If you had used and && when you are looking for values that don’t match, then you can ensure that all of them are true before running the block

(letter !== letters[0] && letter !== letters[1] && letter !== letters[2])

If we evaluate it with letter being ‘c’ now:

(true && true && false)

The last one is false and we were using and && so that means the entire condition is not met.

Conclusion
Ultimately, it didn’t matter you used it incorrectly in this case because your correct one already directed the code. You could have used just an else and got the same effect.

I think a rule of thumb is that if you are looking for the same variable to not equal something in multiple or || clauses, then it isn’t going to do what you expect.

Side Note
You probably haven’t gotten to the lesson yet, but you have some simplified syntax in your future that I think you’re going to like

const degrees = ['Fahrenheit', 'Kelvin', 'Rankine', 'Delisle', 'Newton'];

console.log(degrees.includes('Kelvin')); // true
console.log(degrees.includes('Toasties')); // false

That will make the if conditions a lot easier once you do get to that lesson.

if (degrees.includes(degree)) {
  // In the list
}
if (!degrees.includes(degree)) {
  // Not in the list
}

You don’t need to worry about that yet, just wanted to give you a sneak peek because I have a feeling you’ll go and refactor some of your functions once you do.

Off topic, sort of,

Temperature Scales and Their Inventors

1 Like

As was independently observed and accepted in some form, the temperature of ice and water vapor fit into the picture. They are distinguishable markers in an observable form that we humans can relate to.

Anders Celsius got it right.

Dear @selectall

Regarding:

I believe I’ve understood the thing and it truly simplifies it all. As you said, I’ve liked it a lot:

let temperature;
let degrees = ['Kelvin','Celsius','Fahrenheit', 'Newton'];
let kelvin;
let celsius;
let fahrenheit;
let newton;

const tempConv = (temperature, degree) => {
    if (!degrees.includes(degree)) {
        if (typeof temperature === 'number') {
            return 'Temperature is correct, but degree name is not.';
        } else if (typeof number != 'number') {
            return 'Number is not a number and the degree name is not correct.'
        }
    } else if (degrees.includes(degree)) {
        if (typeof temperature === 'number') {
        switch (degree) {
            case degrees[0]:
                kelvin = temperature;
                celsius = temperature - 273;
                fahrenheit = Math.floor(celsius * (9/5) + 32);
                newton = Math.floor(celsius * (33/100));
                return `${kelvin} in degrees Kelvin is ${celsius} in degrees Celsius, ${fahrenheit} in Fahrenheit, and ${newton} in Newton.`;
                break;
            case degrees[1]:
                celsius = temperature;
                kelvin = celsius + 273;
                fahrenheit = Math.floor(celsius * (9/5) + 32);
                newton = Math.floor(celsius * (33/100));
                return `${celsius} in degrees Celsius is ${kelvin} in degrees Kelvin, ${fahrenheit} in Fahrenheit, and ${newton} in Newton.`;
                break;
            case degrees[2]:
                fahrenheit = temperature;
                celsius = Math.floor((fahrenheit - 32) * 5/9);
                kelvin = celsius + 273;
                newton = Math.floor(celsius * (33/100));
                return `${fahrenheit} in degrees Fahrenheit is ${celsius} in degrees Celsius, ${kelvin} in Kelvin, and ${newton} in Newton.`;
                break;
            case degrees[3]:
                newton = temperature;
                celsius = Math.floor(newton / 0.3);
                kelvin = celsius + 273;
                fahrenheit = Math.floor(celsius * (9/5) + 32);
                return `${newton} in degrees Newton is ${celsius} in degrees Celsius, ${kelvin} in Kelvin, and ${fahrenheit} in Fahrenheit.`;
                break;
        }
    } else if (typeof temperature != 'number') {
            return "Degree's names is correct but temperature is not a number.";  
    }
}
}

console.log(tempConv(293, degrees[0])); // 293 in degrees Kelvin is 20 in degrees Celsius, 68 in Fahrenheit, and 6 in Newton.

console.log(tempConv(20, degrees[1])); // 20 in degrees Celsius is 293 in degrees Kelvin, 68 in Fahrenheit, and 6 in Newton.

console.log(tempConv(68, degrees[2])); // 68 in degrees Fahrenheit is 20 in degrees Celsius, 293 in Kelvin, and 6 in Newton.

console.log(tempConv(6, degrees[3])); // 6 in degrees Newton is 20 in degrees Celsius, 293 in Kelvin, and 68 in Fahrenheit.

console.log(tempConv(2, 'ernesto')); // Temperature is correct, but degree name is not.

console.log(tempConv('a', degrees[1])); // Number is not a number, although the degree name is correct.

console.log(tempConv('a', degrees[5])); // Number is not a number and the degree name is not correct.

Did I get it right?

Other than that, your explanation about how to properly validate using and (&&) and or (||) was pretty clear. I will be back at it as I ever need it again. Thanks so much for it :slight_smile:

I am sad that this week I barely had time to code because of my job. Christmas is around the corner and, as a marketer, my clients are going logically crazy this time of the year to get the most out of Christmas sales… so I spend my days — even my nights — doing all sort of arrangements for them. Anyway, I’ve recently joined Codecademy for a yearly subscription, so I will probably have many other chances to bother you with my questions in the future

Thank you so much for the great help so far (and thank you, @mtf, for your “off-topic of sorts” contributions :heart:).

Cheers!

2 Likes

It looks like you got the array.includes() method down perfectly. I knew you’d like it. It definitely can help simplify things and make the code more readable at the same time.

You may not have been able to code as much this week, but it’s good you’ve been staying busy with work for the holidays. Once things settle down you can take advantage of that yearly subscription. :smiley: Don’t worry, I won’t think of it as a bother at all.

Cheers!

1 Like

A few observations:
You should put your guard clauses at the start.
Also, it is pretty standard to error on each individual issue with each parameter and the user would need to fix then one at a time. So you’d just do:

if (typeof temperature === 'number') 
     return 'Temperature [...]';
if (typeof number != 'number') 
     return 'Number [...]';
if (!degrees.includes(degree))
    return 'Degree's [...]'

Ideally, they wouldn’t be returns but rather throwing appropriate errors. Currently you cannot tell if an error occurred or if the conversion was successful from the return of tempConv without actually looking at the string, errors would avoid that.

If you want to print more detailed information to the user about issues with input, that wouldn’t be a concern of the temperature conversion function. If you wanted all issues the passed in arguements to be returned, I would collate the individual issues into one error/return rather than trying to create a bespoke sentence for each possible combination.

What is number in if (typeof number != 'number')? It isn’t used in the function and isn’t declared in the code, unless I missed it.

Instead of a list containing the unit types, I would create and object like so:

const tempUnit = object.freeze(
    {
        KELVIN: symbol('KELVIN'),
        CELCIUS: symbol('CELCIUS')
    });

const tempConv(degree) {
    switch(degree) {
        case tempUnit.KELVIN:
            // Do stuff
            return 'xyz Kelvins';
       // Rest of the cases
       default:
           // Handle degree not being supported/valid
           return 'error degree is not a valid tempUnit';
    }
}

// Use like so
console.log(tempUnit.KELVIN);

The benefit here is the user knows what the options are and doesn’t have to guess, they won’t get the case wrong etc and they will have (depending on the IDE) the options suggested to them. That probably uses parts of JavaScript you haven’t seen but it can still be simplified to:

const tempUnits = {
    KELVIN: 'Kelvin',
    CELCIUS: 'Celcius'
}

I’d also say the tempConv should just return a number with another function using tempConv to do the conversion and print the nice string to the console. This separates the concernss of conversion and presentation/formatting and also allows tempConv to be more reusable.

These changes will have the benefit of removing all your nesting and will make the code easier to read.