7

I need to test to see if exactly two out of three booleans are true.

Something like this:

if ((a && b && !c) || (a && !b && c) || (!a && b && c)) {
  // success
}

Is this the most direct way to go about this? Does anyone know of a shortcut/shorthand?

Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
WillD
  • 5,170
  • 6
  • 27
  • 56
  • Check [this answer](https://stackoverflow.com/a/3076081/2314737) – user2314737 Dec 21 '18 at 22:17
  • Yeah I saw that one but my question differs because that case is "at least" two of them... which would mean that the third could also be true, but not in my case. – WillD Dec 21 '18 at 22:19

8 Answers8

14

To check if exactly two are equal to true:

[a, b, c].filter(Boolean).length === 2;

References:

David Thomas
  • 249,100
  • 51
  • 377
  • 410
6

If you add the values you can check if the result is 2

if ((a + b + c) == 2) {
    // do something
}
ave4496
  • 2,950
  • 3
  • 21
  • 48
  • thanks. I forgot to consider that booleans are just 1 and 0 in JS. – WillD Dec 21 '18 at 22:23
  • Would you bother to explain why? – ave4496 Dec 21 '18 at 22:42
  • @RichardAyotte In the UK, if you did that the programmer might have grounds for unfair dismissal.. :) – Keith Dec 21 '18 at 22:44
  • If you put it in a function with a useful name it is self explanatory. I just answered his question and assumed he will put the code in a function. – ave4496 Dec 21 '18 at 22:52
  • 1
    @RichardAyotte `cacophemism` Yeah I got that, the reason for the smiley.. It's not really a trick, it's just how JS is, but your point about obvious is totally valid. Doing `Number(a) + Number(b) + Number(c)` although longer, makes it easier for other programmers to see what your intention is. And I'm all for programmers making easy to follow code. – Keith Dec 21 '18 at 23:04
  • Or perhaps `(!a + !b + !c) ==1` to more obviously test only 1 of them is false? – traktor Dec 21 '18 at 23:34
1

I would go this readable (IMO) way:

let conditions = [a && b && !c, a && !b && c, !a && b && c]
if(conditions.filter(c => c).length === 2) { /* ... */}
Nurbol Alpysbayev
  • 19,522
  • 3
  • 54
  • 89
1

You don't really need to even convert them.

let a = true;
let b = true;
let c = false;

if(a + b + c === 2) {
    console.log('You won!');
} else {
    console.log('Not 2');
}
  • Um, that still converts them. (Not that I think this is a bad solution, but clearly there are those who don't like it.) The conversion isn't done here by the `==`, it's the `+` instead which implicitly converts the booleans to numbers here. (In general I think `+` converts the other argument to a string if one is a string already, otherwise it converts them both to numbers.) – Robin Zigmond Dec 21 '18 at 22:36
0

You can just convert (cast) those booleans to integers and add them together. Then check if it's equal to 2. Like this (C):

int res = (int)a + (int)b + (int)c;
if (res == 2) { /* Do something... */ }

EDIT:

For JavaScript you don't even need to cast the values:

const res = a + b + c
if (res == 2) { /* Do something... */ }
comonadd
  • 1,822
  • 1
  • 13
  • 23
0

If you're trying to see if exactly two out of three booleans are true multiple times, you can use a function to shorten your code.

function boolTest(a, b, c) {
    if ((a && b && !c) || (a && !b && c) || (!a && b && c)) {
        return true
    } else {
        return false
    }
}

Then, you can use it like this:

boolTest(true, true, false) // returns true
boolTest(false, true, false) // returns false
R.S.
  • 11
  • 3
0

In JavaScript (and most other modern coding languages), Boolean variables can be stored as binary integers (1 and 0), and those integers can be used as Booleans. See this example:

if (1) {
    console.log("1 is true");
} else {
    console.log("1 is false");
}

if (0) {
    console.log("0 is true");
} else {
    console.log("0 is false");
}

So to do a check for two out of three Booleans, you could do this:

var a = true;
var b = false;
var c = true;

var total = (a ? 1 : 0) + (b ? 1 : 0) + (c ? 1 : 0);
if (total == 2) {
    console.log("Success!");
}

Hopefully this helps!

Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
0

a=true;
b=true;
c=false;
arr = [a,b,c]
result = arr.reduce((acc, cur) => acc+cur) == 2;

console.log(result);

The advantages of this approach are:

  • no conversion to Boolean
  • easy to generalize to arrays of any size / any number of trues

For longer arrays one might consider a better performing solution that stops summing as soon as the desired number is reached

n=2
// large array
arr=[true,true,true].concat(Array(10000).fill(false))

// reduce will stop as soon as result is >n
result = arr.slice(0).reduce((acc, cur, i, a) => {acc+=cur; if (acc>n) a.splice(1); return acc});
console.log(result==2)
user2314737
  • 27,088
  • 20
  • 102
  • 114