How to optimize a large number of if-else if-else expressions

9.3k Views Asked by At

here is the some sample line of codes..

if(loc > 0 || cat > 0 || price > 0 || jsBed <= bedroom || jsBuilt >= built) {    
 /// Condition to checn all true
    return true;
} else if(loc < 0 || cat > 0 || price > 0 || jsBed <= bedroom || jsBuilt >= built) { 
   /////// 1 false other are true 

} else if(loc > 0 || cat < 0 || price > 0 || jsBed <= bedroom || jsBuilt >= built) { 

}

How to handle these condition. if i have 5 statement. Then it must be almost 12+ condition one by one.. if i am checking all the 5 combinations its going to more lines of code do we have any better option to check all the conditions.

5

There are 5 best solutions below

5
On BEST ANSWER

If you treat a boolean expression as an integer in javascript, it will evaluate to 0 (for false) or 1 (for true). So you could sum the conditions and then use a switch-case construct to check how many were true:

var numTrue = 
   (loc > 0) + (cat > 0) + (price > 0) + (jsBed <= bedroom) + (jsBuilt >= built);

switch(numTrue) {
    case 0:
        // do something if no condition is met
        break;
    case 1:
        // do something else if one condition is met
        break;
    // etc...
}
1
On

edit1: modified for javascript, not java. Oops...

I'm not sure if you want to see all combinations, but you can group them by introducing an numeric value for each possible output.

Concretely there are 5 variables and 2 options each variable? I've setup a table with numbers in binary representation. If there are > 2 options each(or at some) variable you have to use numbers (base 10). You can use binary values like

const locVal  = (loc > 0 ? 0x1 : 0x0) << 0;
const catVal  = (cat < 0 ? 0x1 : 0x0) << 1;
const priceVal= (price < 0 ? 0x1 : 0x0) << 2;
ect

So you can group them in a method:

function foo(trueCond, level) {
    return (trueCond ? 0b1 : 0b0) << level;
}

which makes

const locVal  = foo(loc > 0, 0);
const catVal  = foo(cat > 0, 1);
const priceVal= foo(price > 0, 2)

(I have omitted the other vars...) Then add up the binary values

const total = locVal + catVal + priceVal

Then you now have to use a switch case statement like

switch (total) {
    case 0: // all options negative
    case 1: // only loc is positive
    case 2: // only cat is positive
    case 3: // both loc and cat is positive
    ect
}

The values in the case represents the integer value of the binary sequence present in total. It has to be noted that it is extremely important to document the code very well, especially the case blocks, so that other readers can figure out directly which value stands for what (like i did).

If there are more than two options per variable, you can work in factors of 10 (like in method foo, use (trueCond ? 1 : 0) * Math.pow(10, level))

0
On

5 conditions is 2**5, i.e. 32 combinations.

If you want to check for various combination, without repeating the tests, you can bit-shift the individual results and combine them for a switch statement. working with the numbers directly is succinct but not very readable

var loc=1,cat=0,price=0,jsBed=1,bedroom=0,jsbuilt=0,built=1;

let results=[loc > 0,cat > 0,price > 0,jsBed <= bedroom,jsbuilt >= built];
let bits=results.reduce( (accum,current,index)=>accum+(current<<index), 0);
switch(bits){
case 0: // none
 break;
case 3: // first two
 break;
case 4: // third one
 break;
}

modifying this to use constants would make the switch statement more readable

var loc=0,cat=1,price=0,jsBed=1,bedroom=0,jsbuilt=0,built=1;

const locBit=1<<0;
const catBit=1<<1;
const priceBit=1<<2;
const bedBit=1<<3;
const builtBit=1<<4;
let bits=( loc > 0 )*locBit |
         ( cat > 0 )*catBit |
         ( price > 0 )*priceBit |
         ( jsBed <= bedroom )*bedBit |
         ( jsbuilt >= built )*builtBit;
switch(bits){
  case 0:
      console.log("!loc,!cat,!price,!bed,!built");
      break;
  case catBit|locBit:
      console.log("loc,cat,!price,!bed>!built");
      break;
  default:
      console.log(bits);
}

you could use constants to help

3
On

You have condition that will never be met :

if(loc > 0 || cat > 0 || price > 0 || jsBed <= bedroom || jsBuilt >= built){    
    /// Condition to checn all true
    return true;
} else if(loc < 0 || cat > 0 || price > 0 || jsBed <= bedroom || jsBuilt >= built) { 
/////// 1 false other are true 

} else if(loc > 0 || cat < 0 || price > 0 || jsBed <= bedroom || jsBuilt >= built) { 

}

Basically :

  • On the second else if, the condition cat > 0 || price > 0 || jsBed <= bedroom || jsBuilt >= built is useless ebcause already met in the first one. Since you use an else if they will have already enter in the first if. So the only one that matter is loc < 0.
  • Same for last elseif only cat < 0 is relevant.

So it can be rewritten to

if(loc > 0 || cat > 0 || price > 0 || jsBed <= bedroom || jsBuilt >= built){    
    /// Condition to checn all true
    return true;
} else if(loc < 0) { 
/////// 1 false other are true 

} else if(cat < 0) { 

}

This answer assume that the code provided is the one that you're trying to simplify and not a generic sample.

Note : I think you may have not written what you wanted to do, forgetting some AND instead of OR.

4
On

Since your 3 conditions are fixed, you can have them first, followed by others, which can be converted to switch-case.

if(price > 0 || jsBed <= bedroom || jsBuilt >= built) {
    var locCheck = (loc > 0) ? 1 : 0;
    var catCheck = (cat > 0) ? 1 : 0;
    switch(locCheck + catCheck){
        case 0:
            break;
        case 1:
            break;
        case 2:
            break;
        default:
            break;
    }
}