A somewhat painful triple-nested ternary operator

JavascriptIf StatementTernary Operator

Javascript Problem Overview


I went looking through Raphael.js's source code to find out how he converted RGB values to HSB. I found out the function he did it in and I was in the process of converting it to Python when I bumped into this nice triple-nested ternary operator:

H = (C == 0 ? null :
    V == r ? (g - b) / C :
    V == g ? (b - r) / C + 2 :
             (r - g) / C + 4
    );

It threw me for a loop because Python doesn't have the same kind of ternary operator that Javascript does. I spent a while looking over it and eventually hashed this somewhat saner code (using only if/else) out of it:

if (C == 0) {
	H = null;
} else {
	if(V == r) {
		H = (g - b) / C;
	} else {
		if(V == g) {
			H = (b - r) / C + 2;
		} else {
			H = (r - g) / C + 4;
		}
	}
}

Was my interpretation correct? I'm only asking this because if it isn't correct, I'm faced with a lot of debugging. So. Did I "get it"?

Javascript Solutions


Solution 1 - Javascript

To my personal taste, a carefully aligned nested ternary beats the if-else mess:

const H =
  C == 0 ? null            :
  V == r ? (g - b) / C     :
  V == g ? (b - r) / C + 2 :
           (r - g) / C + 4 ;

Solution 2 - Javascript

I think you can have this to avoid the deep nesting:

var H

if(C == 0){
    H = null;
}
else if(V == r){
    H = (g - b) / C;
}
else if (V == g){
    H = (b - r) / C + 2;
}
else {
    H = (r - g) / C + 4;
}

Solution 3 - Javascript

If your JavaScript codebase contains nested ternary statements like the one in question, consider converting the formatting to daisy chained ternary statements instead.

H = (C == 0)           // Is C zero?
    ? null             // Then return `null`, else ...
    : (V == r)         // Is V equal to r?
    ? (g - b) / C      // Then return this value, else ...
    : (V == g)         // Is V equal to g?
    ? (b - r) / C + 2  // Then return this value
    : (r - g) / C + 4; // Otherwise fall back to this default value

> They simply read top to bottom in a straight line, returning a value > as soon as they hit a truthy condition or the fallback. > > –Nested Ternaries are Great, Eric Elliot

Solution 4 - Javascript

The same logic can be written in a simpler way:

var H

if (C == 0)
    H = null;
else if (V == r)
	H = (g - b) / C;
else if (V == g)
	H = (b - r) / C + 2;
else
	H = (r - g) / C + 4;

It's possible to omit the curly braces because there's a single statement in each condition. And given that the conditions are mutually exclusive, using else if is much clearer than nesting ifs.

Solution 5 - Javascript

H = C == 0 
    ? null 
    : V == r 
        ? (g - b) / C 
        : V == g 
            ? (b - r) / C + 2 
            : (r - g) / C + 4

I've seen Dan Abramov using this indentation placement pattern. While I don't like how the conditional operator ? no longer visually follows the condition, I prefer this to something like @lolmaus's example in that the indentation will always be consistent regardless the size of the conditional.

You actually start to look at it as ? true : false which is visually intuitive here. And this way, I find the ternary is much easier to spot and differentiate from the surrounding code.

Solution 6 - Javascript

Yes, it's right (apart from capitalisation differences). Yet, it may be cleaner written without any parentheses, readable as elseif:

if (C == 0)
    h = null;
else if (V == r)
    h = (g - b) / C;
else if (V == g)
    h = (b - r) / C + 2;
else
    h = (r - g) / C + 4;

Solution 7 - Javascript

Here's another, more elegant idea...

if (C != 0) 
{
  if (V == r) return (g - b) / C;
  if (V == g) return (b - r) / C + 2;
  return (r - g) / C + 4;
}

return null;

Just wrap this in function and use instead of H...

Solution 8 - Javascript

As mentioned in MDN Docs:

function example(…) {
    return condition1 ? value1
         : condition2 ? value2
         : condition3 ? value3
         : value4;
}

// Equivalent to:

function example(…) {
    if (condition1) { return value1; }
    else if (condition2) { return value2; }
    else if (condition3) { return value3; }
    else { return value4; }
}

Solution 9 - Javascript

Why not use ternary operators found in Python?

H = (
    None            if C == 0 else
    (g - b) / C     if V == r else
    (b - r) / C + 2 if V == g else
    (r - g) / C + 4
)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionElliot BonnevilleView Question on Stackoverflow
Solution 1 - JavascriptAndrey Mikhaylov - lolmausView Answer on Stackoverflow
Solution 2 - JavascriptJosephView Answer on Stackoverflow
Solution 3 - JavascriptLars Gyrup Brink NielsenView Answer on Stackoverflow
Solution 4 - JavascriptÓscar LópezView Answer on Stackoverflow
Solution 5 - JavascriptssomnoremacView Answer on Stackoverflow
Solution 6 - JavascriptBergiView Answer on Stackoverflow
Solution 7 - Javascriptonedevteam.comView Answer on Stackoverflow
Solution 8 - JavascriptShivam JhaView Answer on Stackoverflow
Solution 9 - JavascriptRarity BelleView Answer on Stackoverflow