简体   繁体   中英

Is there a better looking way to compare 3 values that may or may not be 0 in Javascript?

I'm trying to compare 3 different values that may be 0 or greater. Is the only way to do it with multiple else-if statements? This is what I have right now but I just feel like there must be a better way:

//just A
if (A > 0 && B == 0 && C == 0){//Do something}
//just B
else if (A == 0 && B > 0 && C == 0){//Do something}
//just C
else if (A == 0 && B == 0 && C > 0){//Do something}

//A + B
else if (A > 0 && B > 0 && C == 0){//Do something}
//A + C
else if (A > 0 && B == 0 && C > 0){//Do something}
//B + C
else if (A == 0 && B > 0 && C > 0){//Do something}

//A + B + C
else if (A > 0 && B > 0 && C > 0){//Do something}

else {//Do something}

You could think of each individual check as producing a value of 1 or 0 (true or false). If test values are A=2, B=0, C=99, then the check A > 0 -> true -> 1 and B == 0 -> false -> 0.

So if we combine each variation of the three checks for A, B and C, the results for the test values are as follows:

  • none: A == 0 && B == 0 && C == 0 -> false, false, false -> 000
  • just A: A > 0 && B == 0 && C == 0 -> true, false, false -> 100
  • just C: A == 0 && B == 0 && C > 0 -> false, false, true -> 001
  • just B: A == 0 && B > 0 && C == 0 -> false, true, false -> 010
  • B + C: A == 0 && B > 0 && C > 0 -> false, true, true -> 011
  • A + C: A > 0 && B == 0 && C > 0 -> true, false, true -> 101
  • A + B: A > 0 && B > 0 && C == 0 -> true, true, false -> 110
  • A + B + C: A > 0 && B > 0 && C > 0 -> true, true, true -> 111

You could use binary numbers as keys to an object from which to get the action you would like to execute. This is the variants object in the example. You can replace the console.logs with actual 'do something' logic you need.

What const key = (+;!A << 2) + (+!!B << 1) + !!C; does:

  1. Convert each number to a boolean - !!A -> true, !!B -> false (for the test values (A=2, B=0, C=99)
  2. Convert the boolean to a number - +true -> 1, +false -> 0
  3. Shift it to the appropriate bit position - 1<<2 -> 100 (binary) -> 4 (decimal), 0<<1 is still 0,
  4. Sum the numbers - 4 + 0 + 1 -> 5 -> 0b101

 const variants = { [0b000]() {console.log('none/default')}, [0b001]() {console.log('just C')}, [0b010]() {console.log('just B')}, [0b011]() {console.log('B+C')}, [0b100]() {console.log('just A')}, [0b101]() {console.log('A+C')}, [0b110]() {console.log('A+B')}, [0b111]() {console.log('A+B+C')}, } const A = 2; const B = 0; const C = 99; const key = (+;;A << 2) + (+!!B << 1) + !!C; variants[key]();

Option 2

If using binary numbers and bitwise operations are confusing, you could use string representation of a binary number.

const variants = {
    '000': () => {console.log('none/default')},
    '010': () => {console.log('just B')},
   // the rest of the keys
}
const bitA = A ? 1 : 0;
const bitB = B ? 1 : 0;
const bitC = C ? 1 : 0;

const key = `${bitA}${bitB}${bitC}`;
variants[key]();

You have 3 variables (a, b, c) with 2 possible (> 0 or <= 0) states which means you have 2 3 = 8 cases in total. One way is to represent them as bits

const toBits = (a, b, c) = {
  const toBit = val => val > 0 ? '1' : '0'
  return toBit(a) + toBit(b) + toBit(c)
}

const cases = {
  '000': () => { // do something },
  '001': () => { // do something },
  '010': () => { // do something },
  '011': () => { // do something },
  '100': () => { // do something },
  '101': () => { // do something },
  '110': () => { // do something },
  '111': () => { // do something },
}

const bitsRepresentation = toBits(a, b, c)
const runCase = cases[bitsRepresentation]

runCase()

Another option is to use switch in kinda inverted way

const aFlag = a > 0
const bFlag = b > 0
const cFlag = c > 0

switch (true) {
  case (!aFlag && !bFlag && !cFlag):
    // do something  
  case (!aFlag && !bFlag && cFlag):
    // do something  
  case (!aFlag && bFlag && !cFlag):
    // do something  
  case (!aFlag && bFlag && cFlag):
    // do something  
  case (aFlag && !bFlag && !cFlag):
    // do something  
  case (aFlag && !bFlag && cFlag):
    // do something  
  case (aFlag && bFlag && !cFlag):
    // do something  
  case (aFlag && bFlag && cFlag):
    // do something  
  default:
    // do nothing
}

It really depends on whether you really need to strictly distinguish between all 8 of those scenarios, but if you still need all 8 of those, I guess you could check each of a, b, and c once, and assign them to booleans instead of repeatedly checking them:

aFlag = (A > 0);
bFlag = (B > 0);
cFlag = (C > 0);

//just A
if (aFlag && !bFlag && !cFlag){//Do something}
//just B
else if (!aFlag && bFlag && !cFlag){//Do something}
//just C
else if (!aFlag && !bFlag && cFlag){//Do something}

//A + B
else if (aFlag && bFlag && !cFlag){//Do something}
//A + C
else if (aFlag && !bFlag && cFlag){//Do something}
//B + C
else if (!aFlag && bFlag && cFlag){//Do something}

//A + B + C
else if (aFlag && bFlag && cFlag){//Do something}

else {//Do something}

This probably isn't much faster, but, at least in my opinion, it seems a bit easier to look at.

I guess you could also change it to some form of nested if statements, rather than a linear series of else-if statements:

if (A > 0) {
    if (B > 0) {
        if (C > 0) {
            //A + B + C
        } else {
            //A + B
        }
    } else {
        if (C > 0) {
            //A + C
        } else {
            //just A
        }
    }
} else {
    if (B > 0) {
        if (C > 0) {
            //B + C
        } else {
            //just B
        }
    } else {
        if (C > 0) {
            //just C
        } else {
            //None
        }
    }
}

This looks really messy, but it would only do 3 checks total, instead of a possible 7 for your implementation.

You cannot reduce the else if statements but you can reduce the conditions inside each if condition. I would suggest to make a sum of all 3 variables and check whether particular value is matching with sum or not.

Here is my suggestion:

const sum = A + B + C;
//just A
if (A == sum){//Do something
}
//just B
else if (B == sum){//Do something
}
//just C
else if (C == sum){//Do something
}

//A + B
else if (A + B == sum){//Do something
}
//A + C
else if (A + C  == sum){//Do something
}
//B + C
else if (B + C  == sum){//Do something
}

//A + B + C
else if (A + B + C == sum){//Do something
}

else {//Do something
}

As per the question I am assuming you have A, B and C are numbers and greater or equal to 0.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM