5

I have a simple bit of code that checks some conditions, and I want each condition to cause a unique output, but if no conditions are met then to cause another unique output.

Is there any way to create an else that is only triggered if all previous if statements fail? I am aware that the below code carries out the same purpose, but it seems cumbersome and it would be nicer to have a quicker way of checking all of the variables than copy and paste all of them into another if statement.

var boolean1 = true,
  boolean2 = true,
  boolean3 = false;

if (boolean1) {
  alert("boolean1");
}
if (boolean2) {
  alert("boolean2");
}
if (boolean3) {
  alert("boolean3");
}
/* and so on */
if (!boolean1 && !boolean2 && !boolean3 /* etc */ ) {
  alert("none");
}

7
  • 3
    switch with a default. See switch. Commented Jan 18, 2017 at 18:34
  • 2
    it would potentially be easier, if the booleans would be in an array, is that possible? Commented Jan 18, 2017 at 18:35
  • 1
    @zero298 — No: looks for the first case clause whose expression evaluates to the same value as the result of the input expression. If boolean1 is true, it won't check the boolean2 case. Commented Jan 18, 2017 at 18:39
  • @zero298 My understanding is switch case evaluates based on the outcome of one expression. This one deals with many Boolean variables, is that possible with switch case? Commented Jan 18, 2017 at 18:41
  • the accepted answer here gives a shortcut to this problem stackoverflow.com/questions/3463833/… Commented Jan 18, 2017 at 18:45

12 Answers 12

1

To make this scale, you will need to change your data structure to something you can iterate over. That way your processing logic remains the same and you can supply any size input. Here's one implementation where I use an object with properties representation your Boolean values. The checkResults function below iterates over the property names in the object, checks the value for each one, and performs an alert and sets a flag if any value is true. At the end it checks if any value was true and alerts with that case.

function checkResults(resultMap) {
    var any = false;
    Object.keys(resultMap).forEach(function(key) {
        if (resultMap[key] === true) {
          any = true;
          alert(key);
        }
    });
    if (!any)
      alert('none');
}

checkResults({
  'boolean1': false,
  'boolean2': true,
  'boolean3': false
});

You can build your input object property by property if you have to:

var results = {};
results['boolean1'] = true;
results['boolean2'] = false;
...
checkResults(results);

And the checkResults function always stays the same.

Sign up to request clarification or add additional context in comments.

2 Comments

Accepting this as the answer as it is the most compact method I've seen. As a side note, adding a second object that stores a string for each result (e.g. the "alert('boolean1')") that is called with an eval("script string goes here") would make it compatible for other code blocks.
@PhilipEagles: True, but there's no need for eval or even a second object -- in fact, if you ever find yourself using eval, you've got a smell that needs to be removed. You could alter this to use an array of objects that contains your "rules": [{ name: 'boolean1', value: true, message : function() { alert('boolean1 was bad!'); }, ...]. Then you can adjust the function to loop over the array objects and invoke the message function stored there.
1

The only other way I can see to do this is for each function to set a different boolean and then test that.

var boolean1 = true,
    boolean2 = true,
    boolean3 = false,
    any = false;


if (boolean1) {
  alert("boolean1");
  any = true;
}
if (boolean2) {
  alert("boolean2");
  any = true;
}
if (boolean3) {
  alert("boolean3");
  any = true;
}
/* and so on */
if (!any) {
  alert("none")
}

This probably isn't much of an improvement though.

Comments

1

You could reduce the array of entries and return either the result of the former iteration if the boolean value is false or true in the other case. Finally check the returned value and show a message.

function checkResults(results) {
    const
        check = results => Object
            .entries(results)
            .reduce((r, [k, v]) =>  {
                if (!v) return r;
                console.log(k);
                return true;
            }, false);

    if (!check(results)) console.log('none');
}

checkResults({ boolean1: false, boolean2: true, boolean3: true });
checkResults({ boolean1: false, boolean2: false, boolean3: false });

Comments

0

You could maintain a flag which when passes the condition alerts none

var boolean1 = true;
var boolean2 = true;
var boolean3 = false;
var allConditionFailed = true;

if (boolean1) {
  alert("boolean1");
  allConditionFailed = false;
}
if (boolean2) {
  alert("boolean2");
  allConditionFailed = false;
}
if (boolean3) {
  alert("boolean3");
  allConditionFailed = false;
}

if(allConditionFailed) {
   alert("none");
}

Comments

0
var accumulated = false;

acumulated = acumulated || boolean1;
if (boolean1) {
  alert("boolean1");
}

acumulated = acumulated || boolean2;
if (boolean2) {
  alert("boolean2");
}

acumulated = acumulated || boolean3;
if (boolean3) {
  alert("boolean3");
}

if(!acumulated) {
  alert("none");
}

Comments

0

No, there is none. Just imagine the control flow diagram for your code, there's no way to convert that to a structured program (or even an unstructured one) without evaluating a boolean in multiple places or without introducing helper variables.

If you want to check every condition only once (in the execution I mean, not in the code), you could do

if (boolean1) {
  alert("boolean1");
  if (boolean2) {
    alert("boolean2");
  }
  if (boolean3) {
    alert("boolean3");
  }
} else {
  if (boolean2) {
    alert("boolean2");
    if (boolean3) {
      alert("boolean3");
    }
  } else {
    if (boolean3) {
      alert("boolean3");
    } else {
      alert("none")
    }
  }
}

but that is arguably much uglier than your original solution.

I suspect what you actually want is an array of options:

var booleans = [true, true, false];
var alerts = ["boolean1", "boolean2", "boolean3"];
for (var i=0; i<booleans.length; i++)
  if (booleans[i])
    alert(alerts[i]);
if (booleans.every(b => !b))
  alert("none");

Comments

0

If you can save them as an array then you can use array.indexOf() to make sure that true doesn't exist in the array (all tests fail), and if it does loop through the array with array.forEach() to do something with each of them.

So your code will look something like this:

// The array of conditions.
var bools = [true, true, false];

// Check if none of them are true (all fail).
if (bools.indexOf(true) === -1) {
    alert("none");
} else {
// Loop over them and do something based if the current one is true.
bools.forEach(function(b, i) {
    b ? alert("boolean" + (i + 1)) : '';
});
};

Comments

0

if an array is possible try this:

var booleans = [false, false, false];
var i = 0;
while (i < booleans.length) {
    if (booleans[i] === true) {
        alert("boolean"+i);
    }
    i++;
}
i = 0;
while (booleans[i] === false && i < booleans.length) {
    i++;
}
if (i == booleans.length) {
    alert('none');
}

// Filter would work like this:
var bools = booleans.filter(function (val, ind) { return !val; });
if (bools.length  > 0) alert('none');

You can read more about filter() here: https://msdn.microsoft.com/de-de/library/ff679973(v=vs.94).aspx

Other possibilities are using .every() as @Bergi mentioned.

2 Comments

it is also possible to use array functions such as filter, if your javascript edition supports it, but I did not show this here.
could you explain the filter function you mention? I'm not entirely sure what you mean by it.
0
var boolean1 = true,
    boolean2 = true,
    boolean3 = false;

if(boolean1 || boolean2 || boolean3) {

    if (boolean1) {
        alert("boolean1");
    }
    if (boolean2) {
        alert("boolean2");
    }
    if (boolean3) {
        alert("boolean3");
    }

} else {
    alert("none");
}

When all booleans are false, it checks only one condition and runs the else part directly. If true, it checks four if-conditions, that are also checked on starting, so it is the better one.

Comments

0
you can use this alternative approach
    var boolean1 = true,
  boolean2 = true,
  boolean3 = false;

let anyConditionMet = false;

if (boolean1) {
  alert("boolean1");
  anyConditionMet = true;
}
if (boolean2) {
  alert("boolean2");
  anyConditionMet = true;
}
if (boolean3) {
  alert("boolean3");
  anyConditionMet = true;
}

if (!anyConditionMet) {
  alert("none");
}

2 Comments

This is duplicated to Quentin's answer
yes i think both are almost same didn't notice that
-1

This is not super readable but this would work:

var boolean1 = true,
    boolean2 = true,
    boolean3 = false;

[(boolean1 && !alert("boolean1")),
    (boolean2 && !alert("boolean2")),
      (boolean3 && !alert("boolean3"))]
      .some(function(passed) {
        return passed;
      }) || alert("none");

1 Comment

Actually that doesn't work, as alert always returns undefined.
-1

you can use a for loop to reduce the size of the code.

var boolean1 = true,
  boolean2 = true,
  boolean3 = false;
  none=true;
for(i=1;i<4;i++){
    var variable=window["boolean"+i];
    if (variable) {
      alert("boolean"+i);
      none=false;
    }
}

if (none) {
  alert("none");
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.