610

An interviewer recently asked me this question: given three boolean variables, a, b, and c, return true if at least two out of the three are true.

My solution follows:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a && b) || (b && c) || (a && c)) {
        return true;
    }
    else{
        return false;
    }
}

He said that this can be improved further, but how?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user282886
  • 3,125
  • 8
  • 22
  • 11
  • 173
    Inline the return statement. – Finglas Jun 19 '10 at 15:48
  • 82
    `atLeastTwo(iWantYou, iNeedYou, imEverGonnaLoveYou)` – Andrew Grimm Jun 20 '10 at 07:44
  • 1
    Had it been C, you could just add the booleans together. Perhaps this was what he was thinking of, but forgot Java cannot do that? – Thorbjørn Ravn Andersen Jun 20 '10 at 08:25
  • 6
    Thorbjørn: Doesn't C use zero/nonzero for bools? I don't think that would even work in C, e.g., `atLeastTwo(0,2,0)`. – Ken Jun 20 '10 at 14:52
  • 1
    Your interviewer should define 'improved' before you can do anything else. Inlining the if/else would be reasonable, but anything more is simply proving how clever they are. – Ash Jun 21 '10 at 07:32
  • 3
    Ken, you could use !! to make sure that the value was either 1 or 0, i.e. (!!A + !!B + !!C)>=2 Still, the ?: version given below is better. – Rune Aamodt Jun 21 '10 at 19:06
  • 2
    @Ken: According to C99, whenever you cast from a `bool` you always get either 0 or 1. Therefore, adding them together would always work in C99. – Dietrich Epp Jun 22 '10 at 00:46
  • 3
    LOL, this is what my functional programming teacher would call "Boolean fear": instead of using the perfectly acceptable result of a boolean expression, using a control structure to wrap it and return either True or False. Apparently it looks reassuring when you see exactly what you are returning, instead of trusting the logic operators. – dguaraglia Jun 22 '10 at 03:54
  • 5
    return true; //math joke : if vs if and only if – paperhorse Jun 22 '10 at 10:19
  • 93
    Why do people upvote the most trivial questions? – BlueRaja - Danny Pflughoeft Jun 22 '10 at 16:45
  • 4
    Seriously, how does this get 78 upvotes? – Davy8 Jun 22 '10 at 18:44
  • 52
    Questions that are general and easy to understand get a lot of up votes. Questions that are very specific and technical don't. – Jay Jun 23 '10 at 17:37
  • Should a separate question be asked about how you'd do this in your favorite language, and non-java answers moved there? – Andrew Grimm Jul 05 '10 at 03:33
  • Not only upvoting, but people are even marking it as a favourite (47 favourites now). Woow. – Albus Dumbledore Aug 12 '10 at 11:00
  • 1
    @BlueRaja-DannyPflughoeft the simple questions get upvoted, because everyone understands them, and this question actually got a few good answers as well. – Paul Wagland Sep 19 '11 at 19:17
  • 1
    125 interviewers have favorited this question. And they will get what they deserve ;) – fontno May 23 '13 at 06:15
  • you can write a method as getTrueValuesSize(boolean[] values) { List trueValues = new ArrayList(); for (int i = 0; i < values.length; i++) { if (values[i] == true) { trueValues.add(bolArray[i]); } }} // when the number of condition increases it will be hard to maintain and error prone if missed the condition or closing the brackets propertly. – user2323036 Mar 10 '14 at 10:31
  • @BlueRaja-DannyPflughoeft, http://en.wikipedia.org/wiki/Parkinson's_law_of_triviality – Sebastian Apr 24 '14 at 13:55
  • 2
    It depends on what "improve" means here, readability or performance. – kenju Aug 21 '15 at 00:34

65 Answers65

844

Rather than writing:

if (someExpression) {
    return true;
} else {
    return false;
}

Write:

return someExpression;

As for the expression itself, something like this:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return a ? (b || c) : (b && c);
}

or this (whichever you find easier to grasp):

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return a && (b || c) || (b && c);
}

It tests a and b exactly once, and c at most once.

References

Jonas Czech
  • 12,018
  • 6
  • 44
  • 65
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • 150
    +1: lovely solution to the puzzle, but hopefully we don't see anything like this in the real world :) – Juliet Jun 19 '10 at 16:02
  • 125
    @Juliet: I don't know, I think if this was a real-world requirement (with real variable names) it would read pretty well. Consider `return hasGoodAttendance ? (passedCoursework || passed Exam) : (passedCoursework && passedExam)`, that looks fine to me. – Andrzej Doyle Jun 19 '10 at 18:30
  • 3
    I love how every other answer is trying to optimize, while that's obviously not what the interviewer wanted to hear. – Jorn Jun 19 '10 at 20:54
  • 18
    I don't think that looks *bad*, but if the requirement in the domain is understood to be "at least two", I think it'd be easier to read `atLeastTwo(hasgoodAttendance, passedCoursework, passedExam)`. The idea of "at least 2 bools are true" is generic enough to deserve its own function. – Ken Jun 19 '10 at 23:33
  • 1
    Jorn: can you elaborate? I would think that basic optimization is something that most programmers do instinctively. If you're trying to solve a problem, you're naturally going to go for the optimal route. Additionally, the poster wrote that the interviewer noted that his answer could be improved. And if you're being interviewed for a job, then you'd want your answer to be better than the other applicants'. Shooting for "just good enough" usually _isn't_ good enough. – Lèse majesté Jun 20 '10 at 00:12
  • 18
    @Lese: Asking the most micro-optimized code in face to face interviews is impractical, and dare I say, useless. Micro-optimizations, when driven by the need, is guided by runtime profiling results, not human instincts (which are known to be terrible). You can certainly ask interviewees the process by which you'd optimize this further; that's more important than the result itself. – polygenelubricants Jun 20 '10 at 06:05
  • I don't agree with Juliet--it's a creative solution but I normally wouldn't answer such a thing with code I wouldn't want to see in the real world. – Loren Pechtel Jun 21 '10 at 22:32
  • 18
    The ternary operator is a common idiom that you should be able to read. If you can't read it you should study it until you can. Use of the ternary operator is not something I consider "clever" in the derogatory sense. But yes, I'd put this as the body of a method call if you're commonly using the "at least two" logic. – Stephen P Jun 22 '10 at 00:14
  • In real-world situations, I'm a sucker for readability. I would actually use the function "isAtLeastTwo(e1,e2,e3)" instead of directly using ?: in the code. – Uri Jun 22 '10 at 16:45
  • 3
    So elegant. I must admire the beauty for a while longer. I will sit here and bask in it until my boss comes by. – MattC Jun 22 '10 at 19:16
  • Although, the question specifies two booleans must be true. If I'm reading this correctly, it will return true if at least two of these are false as well, correct? – MattC Jun 22 '10 at 19:17
  • @MattC: No. You're not reading it correctly. But imagine that it did return true in both scenarios: what would that be equivalent to? – walkytalky Jun 23 '10 at 13:02
  • 1
    In the last example, you should put parentheses around `a && (b || c)`. Relying on the readers knowledge of operator precedence of `&&` and `||` is bad style. – Tomas Jun 28 '12 at 12:17
  • 1
    The second example is not equivalent to the first, so the text is currently slightly incorrect. If `a` is true and `b` and `c` are both false, `b` will be tested twice. – audun Jul 26 '15 at 16:25
  • 1
    I would not have an issue with finding this in the real world, for one reason only - the name of the method `atLeastTwo`. This says exactly what it does. If I need to understand how, I can study it; and if I don't, I can just believe the method name. If this expression were in the middle of a method that did something else, then I would not allow it through code review. – Dawood ibn Kareem Dec 21 '17 at 04:19
  • After an All Nighter, I thought I would not be able to find a good solution to this -- but this looks good. Yes, I have a similar situation where I want only 1 of 3 conditions to be true. Here it is only 1 conditions to be false. – anjanb Nov 07 '19 at 22:26
510

Just for the sake of using XOR to answer a relatively straight-forward problem...

return a ^ b ? c : a
Tim Stone
  • 19,119
  • 6
  • 56
  • 66
227

Why not implement it literally? :)

(a?1:0)+(b?1:0)+(c?1:0) >= 2

In C you could just write a+b+c >= 2 (or !!a+!!b+!!c >= 2 to be very safe).

In response to TofuBeer's comparison of java bytecode, here is a simple performance test:

class Main
{
    static boolean majorityDEAD(boolean a,boolean b,boolean c)
    {
        return a;
    }

    static boolean majority1(boolean a,boolean b,boolean c)
    {
        return a&&b || b&&c || a&&c;
    }

    static boolean majority2(boolean a,boolean b,boolean c)
    {
        return a ? b||c : b&&c;
    }

    static boolean majority3(boolean a,boolean b,boolean c)
    {
        return a&b | b&c | c&a;
    }

    static boolean majority4(boolean a,boolean b,boolean c)
    {
        return (a?1:0)+(b?1:0)+(c?1:0) >= 2;
    }

    static int loop1(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority1(data[i], data[j], data[k])?1:0; 
                sum += majority1(data[i], data[k], data[j])?1:0; 
                sum += majority1(data[j], data[k], data[i])?1:0; 
                sum += majority1(data[j], data[i], data[k])?1:0; 
                sum += majority1(data[k], data[i], data[j])?1:0; 
                sum += majority1(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static int loop2(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority2(data[i], data[j], data[k])?1:0; 
                sum += majority2(data[i], data[k], data[j])?1:0; 
                sum += majority2(data[j], data[k], data[i])?1:0; 
                sum += majority2(data[j], data[i], data[k])?1:0; 
                sum += majority2(data[k], data[i], data[j])?1:0; 
                sum += majority2(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static int loop3(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority3(data[i], data[j], data[k])?1:0; 
                sum += majority3(data[i], data[k], data[j])?1:0; 
                sum += majority3(data[j], data[k], data[i])?1:0; 
                sum += majority3(data[j], data[i], data[k])?1:0; 
                sum += majority3(data[k], data[i], data[j])?1:0; 
                sum += majority3(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static int loop4(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority4(data[i], data[j], data[k])?1:0; 
                sum += majority4(data[i], data[k], data[j])?1:0; 
                sum += majority4(data[j], data[k], data[i])?1:0; 
                sum += majority4(data[j], data[i], data[k])?1:0; 
                sum += majority4(data[k], data[i], data[j])?1:0; 
                sum += majority4(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static int loopDEAD(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majorityDEAD(data[i], data[j], data[k])?1:0; 
                sum += majorityDEAD(data[i], data[k], data[j])?1:0; 
                sum += majorityDEAD(data[j], data[k], data[i])?1:0; 
                sum += majorityDEAD(data[j], data[i], data[k])?1:0; 
                sum += majorityDEAD(data[k], data[i], data[j])?1:0; 
                sum += majorityDEAD(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static void work()
    {
        boolean [] data = new boolean [10000];
        java.util.Random r = new java.util.Random(0);
        for(int i=0;i<data.length;i++)
            data[i] = r.nextInt(2) > 0;
        long t0,t1,t2,t3,t4,tDEAD;
        int sz1 = 100;
        int sz2 = 100;
        int sum = 0;

        t0 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop1(data, i, sz1, sz2);

        t1 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop2(data, i, sz1, sz2);

        t2 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop3(data, i, sz1, sz2);

        t3 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop4(data, i, sz1, sz2);

        t4 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loopDEAD(data, i, sz1, sz2);

        tDEAD = System.currentTimeMillis();

        System.out.println("a&&b || b&&c || a&&c : " + (t1-t0) + " ms");
        System.out.println("   a ? b||c : b&&c   : " + (t2-t1) + " ms");
        System.out.println("   a&b | b&c | c&a   : " + (t3-t2) + " ms");
        System.out.println("   a + b + c >= 2    : " + (t4-t3) + " ms");
        System.out.println("       DEAD          : " + (tDEAD-t4) + " ms");
        System.out.println("sum: "+sum);
    }

    public static void main(String[] args) throws InterruptedException
    {
        while(true)
        {
            work();
            Thread.sleep(1000);
        }
    }
}

This prints the following on my machine (running Ubuntu on Intel Core 2 + sun java 1.6.0_15-b03 with HotSpot Server VM (14.1-b02, mixed mode)):

First and second iterations:

a&&b || b&&c || a&&c : 1740 ms
   a ? b||c : b&&c   : 1690 ms
   a&b | b&c | c&a   : 835 ms
   a + b + c >= 2    : 348 ms
       DEAD          : 169 ms
sum: 1472612418

Later iterations:

a&&b || b&&c || a&&c : 1638 ms
   a ? b||c : b&&c   : 1612 ms
   a&b | b&c | c&a   : 779 ms
   a + b + c >= 2    : 905 ms
       DEAD          : 221 ms

I wonder, what could java VM do that degrades performance over time for (a + b + c >= 2) case.

And here is what happens if I run java with a -client VM switch:

a&&b || b&&c || a&&c : 4034 ms
   a ? b||c : b&&c   : 2215 ms
   a&b | b&c | c&a   : 1347 ms
   a + b + c >= 2    : 6589 ms
       DEAD          : 1016 ms

Mystery...

And if I run it in GNU Java Interpreter, it gets almost 100 times slower, but the a&&b || b&&c || a&&c version wins then.

Results from Tofubeer with the latest code running OS X:

a&&b || b&&c || a&&c : 1358 ms
   a ? b||c : b&&c   : 1187 ms
   a&b | b&c | c&a   : 410 ms
   a + b + c >= 2    : 602 ms
       DEAD          : 161 ms

Results from Paul Wagland with a Mac Java 1.6.0_26-b03-383-11A511

a&&b || b&&c || a&&c : 394 ms 
   a ? b||c : b&&c   : 435 ms
   a&b | b&c | c&a   : 420 ms
   a + b + c >= 2    : 640 ms
   a ^ b ? c : a     : 571 ms
   a != b ? c : a    : 487 ms
       DEAD          : 170 ms
oliverpool
  • 1,624
  • 13
  • 30
Rotsor
  • 13,655
  • 6
  • 43
  • 57
  • 4
    `a+b+c >= 2` : this doesn't work with negatives, right? You may have to do the `!!a` thing, I'm not sure. – polygenelubricants Jun 19 '10 at 15:52
  • 8
    -1. You should never do that for C. You don't know what the value of true is (it could just as easily be -1). Actually I guess C99 includes in its standard that true is defined as 1. But I still wouldn't do this. – Mark Peters Jun 19 '10 at 15:52
  • 1
    Is that possible if your input is result of boolean operations? And is that possible for "bool" type in C++? – Rotsor Jun 19 '10 at 15:58
  • 2
    @Rotsor: Nobody said the input has to be the result of boolean operations. Even without negatives you're playing with fire, as if you define it as 2 your condition would have false positives. But I don't care about that as much as I dislike the idea of intermingling booleans into arithmetic. Your Java solution is clear in that it does not rely on nuanced conversions from boolean to an integer type. – Mark Peters Jun 19 '10 at 16:05
  • 1
    unexpected... and happy to be wrong... updating my answer slightly – TofuBeer Jun 19 '10 at 19:51
  • 1
    Actually, I didn't expect it too. I thought that straightforward ab|bc|ac would be unbeatable. – Rotsor Jun 19 '10 at 19:55
  • One more surprise to me! It seems that result depends not on the runtime environment, but on the compiler. If I compile with *javac.exe*, then I get results similar to what TofuBeer got. If I compile with Eclipse builder, then I get my results published earlier. – Rotsor Jun 19 '10 at 20:17
  • 7
    Be cautious with microbenchmarks: http://java.sun.com/docs/hotspot/HotSpotFAQ.html#benchmarking_simple – BalusC Jun 19 '10 at 20:32
  • 1
    BalusC, thank you. I split the benchmark into several smaller methods for HotSpot convenience and now it seems to run equally fast with all compilers. – Rotsor Jun 19 '10 at 21:41
  • Obviously, these results suggest you should use the DEAD method. – Justin K Jun 21 '10 at 18:24
  • What does the !! do? Does that NOT NOT, or basically true->false->true? – Anthony D Jun 21 '10 at 18:32
  • This has to be some of the most awful repetitive code I've ever seen. I don't think I could trust it's outcome whatever it may be... – joshperry Jun 21 '10 at 22:54
  • @joshperry Can't use virtual methods in performance-critical places, sorry. I wonder why such a poor question attracted so much attention anyway... I almost doubled my rep. and got my first "Good Answer" badge for doing a useless benchmark. :) – Rotsor Jun 22 '10 at 15:45
  • @Anthony D: I'm not a C user, but I would guess it normalizes a boolean value to some standard definition of true/false. So `!5 == 0`, `!!5 == !(!5) == !(0) == 1` – Mark Peters Jun 22 '10 at 19:16
  • @Rotsor: Hey, my highest score to date is for my answer to "What's your favorite programmer joke". All that hard work testing code on some of my answers, the brilliant insights from years of experience, and my best score comes from a joke. – Jay Jun 23 '10 at 17:24
  • a + b + c <= 2 can be improved even further to (a + b + c) >> 1 – ruslik Jul 21 '10 at 01:40
  • This solution is great, as it can be easily adepted to other problems, such as at least 2 out of 4 or at least 3 out of 4. Thanks! – Martin Thoma Jun 08 '11 at 09:32
  • a&&b || b&&c || a&&c : 394 ms a ? b||c : b&&c : 435 ms a&b | b&c | c&a : 420 ms a + b + c <= 2 : 640 ms a ^ b ? c : a : 571 ms a != b ? c : a : 487 ms DEAD : 170 ms These results from from a Mac Java 1.6.0_26-b03-383-11A511 – Paul Wagland Sep 19 '11 at 19:08
  • What does the `?` operator do? What does the `:` operator do? – Aaron Franke Apr 27 '17 at 16:23
  • These can only be used together and therefore they don't count as individual operators, but rather as one [ternary operator](https://en.wikipedia.org/wiki/%3F:). The informal meaning of `A ? B : C` is "if A then B else C". – Rotsor Apr 29 '17 at 13:53
161
return (a==b) ? a : c;

Explanation:

If a==b, then both are true or both are false. If both are true, we have found our two true booleans, and can return true (by returning a). If both are false there cannot be two true booleans even if c is true, so we return false (by returning a). That's the (a==b) ? a part. What about : c ? Well if a==b is false, then exactly one of a or b must be true, so we have found the first true boolean, and the only thing left that matters is if c is also true, so we return c as the answer.

Boann
  • 48,794
  • 16
  • 117
  • 146
pdox
  • 1
  • 1
  • 1
  • 3
146

This kind of questions can be solved with a Karnaugh Map:

      | C | !C
------|---|----
 A  B | 1 | 1 
 A !B | 1 | 0
!A !B | 0 | 0
!A  B | 1 | 0

from which you infer that you need a group for first row and two groups for first column, obtaining the optimal solution of polygenelubricants:

(C && (A || B)) || (A && B)  <---- first row
       ^
       |
   first column without third case
Jack
  • 131,802
  • 30
  • 241
  • 343
  • 11
    @Justin, The Karnaugh map reduced the number of logical operations from 3 ANDs and 2 ORs to 2 ANDs and 2 ORs. @Jack, Thanks for reminding me of the Karnaugh Map's existence. – Tachy Jun 21 '10 at 20:33
  • 15
    +1 for something new. My next functional spec will include a K-map, whether it needs it or it. – Justin R. Jun 22 '10 at 07:00
  • 2
    Maybe the poor readability can be compensated by (1) the appropriate table in comment and (2) the appropriate unit test... +1 for something useful learned at school. – moala Feb 02 '12 at 15:39
145

Readability should be the goal. Someone who reads the code must understand your intent immediately. So here is my solution.

int howManyBooleansAreTrue =
      (a ? 1 : 0)
    + (b ? 1 : 0)
    + (c ? 1 : 0);

return howManyBooleansAreTrue >= 2;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
danatel
  • 4,844
  • 11
  • 48
  • 62
34

You don't need to use the short circuiting forms of the operators.

return (a & b) | (b & c) | (c & a);

This performs the same number of logic operations as your version, however is completely branchless.

moonshadow
  • 86,889
  • 7
  • 82
  • 122
  • 11
    Why would you want to force 5 evaluations when 1 could do? It really doesn't perform the same number of logic operations in truth. In fact, it would **always** perform more. – Mark Peters Jun 19 '10 at 15:59
  • 2
    I think mixing binary arithmetic and boolean arithmetic is a bad idea. It is like driving screws in the wall with a wrench. Worst of all is they have different semantics. – Peter Tillemans Jun 19 '10 at 16:00
  • 12
    @Mark - it might be faster ... depending on the effect of an incorrect branch prediction on the CPU pipeline. However, it is best to leave such micro-optimizations to the JIT compiler. – Stephen C Jun 19 '10 at 16:04
  • @Stephen C: OK, I see where he's coming from now but agree that's not something you should be doing explicitly in Java. Unfortunately I apparently can't remove my down-vote unless he edits it. – Mark Peters Jun 19 '10 at 16:10
  • 4
    It is fine to do something like this in Java (or any other language)... with a couple of caveats: 1) it needs to be faster (in this case, I believe it is, see my second answer) 2) preferable significantly faster (not sure if it is), 3) most importantly documented since it is "odd". As long as it serves a purpose and it is documented it is fine to "break the rules" when it makes sense. – TofuBeer Jun 19 '10 at 16:17
  • 11
    @Peter Tillemans There is no mixing with binary operators, in Java these are boolean operators. – starblue Jun 19 '10 at 17:28
  • 1
    return ((a|b) & c) | (a & b) uses 4 logical operators instead of 5. Note that (a|b) and (a^b) both work with this formula. – flanglet Apr 01 '12 at 20:23
30

Here's a test-driven, general approach. Not as "efficient" as most of the solutions so far offered, but clear, tested, working, and generalized.

public class CountBooleansTest extends TestCase {
    public void testThreeFalse() throws Exception {
        assertFalse(atLeastTwoOutOfThree(false, false, false));
    }

    public void testThreeTrue() throws Exception {
        assertTrue(atLeastTwoOutOfThree(true, true, true));
    }

    public void testOnes() throws Exception {
        assertFalse(atLeastTwoOutOfThree(true, false, false));
        assertFalse(atLeastTwoOutOfThree(false, true, false));
        assertFalse(atLeastTwoOutOfThree(false, false, true));
    }

    public void testTwos() throws Exception {
        assertTrue(atLeastTwoOutOfThree(false, true, true));
        assertTrue(atLeastTwoOutOfThree(true, false, true));
        assertTrue(atLeastTwoOutOfThree(true, true, false));
    }

    private static boolean atLeastTwoOutOfThree(boolean b, boolean c, boolean d) {
        return countBooleans(b, c, d) >= 2;
    }

    private static int countBooleans(boolean... bs) {
        int count = 0;
        for (boolean b : bs)
            if (b)
                count++;
        return count;
    }
}
Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
  • 9
    Wow, I've never seen a **fully** tested method before seeing this one. – Rotsor Jun 19 '10 at 20:41
  • 52
    I personally find this code awful, for so many reasons. I'm not going to downvote, but if I ever saw this in production code I would curse. An extremely simple boolean operation does not need to be complicated like this. – CaptainCasey Jun 21 '10 at 05:41
  • 11
    I'd be very interested to know your reasons, @CaptainCasey. I think this is pretty good code. There's a nice generalized function that's easy to understand, easy to verify, and a specific function that takes advantage of it, also easy to understand & verify. In the real world, I'd make them public and put them in another class; other than that - I'd happily put this code into production. Oh - yeah - I'd rename countBooleans() to countTrue(). – Carl Manaster Jun 21 '10 at 13:42
  • 1
    @Carl - your code is spending a lot of time creating temporary boolean arrays. Very strange for profiling performance. – jmucchiello Jun 21 '10 at 21:45
  • 2
    @Carl: I'd say that this code is overgeneralized. Most of the single-method solutions from other answers are equally easy to understand and verify. So unless you have another use for `countBooleans` elsewhere in your code there's no reason to have two methods where one does fine. – Rafał Dowgird Jun 22 '10 at 07:54
  • 5
    if its not about performance, this solution looks nearly perfect for me: very easy to read and extendable. Thats exactly what var-args are made for. – atamanroman Jun 22 '10 at 09:17
  • @Michael, @Krougan: Not a joke. I am well aware that my solution isn't as performant as the others; I think it's clearer and more general, and I think that has value. You're entitled to your contrary opinion, of course. – Carl Manaster Jun 22 '10 at 17:53
  • 1
    I sort of admire the sheer psychotic religious doggedness of this, but please just shoot me if I *ever* write code like it. (And no, performance is not the issue.) – walkytalky Jun 22 '10 at 21:04
  • 3
    @walkytalky I'd rather exercise psychotic religious doggedness with respect to correctness, clarity, and generality than to clipping off that one last machine instruction; I think there is much greater value in that, with today's platforms. YMMV. – Carl Manaster Jun 23 '10 at 05:03
  • 4
    @Carl Was my final sentence somehow unclear? I couldn't care less about that last machine instruction. Writing half a page of scripture in place of a simple expression is not clarity at all, it is obfuscation. And if the only way you can think of to demonstrate correctness is absolute exhaustion then how do you ever get anything done? – walkytalky Jun 23 '10 at 07:59
  • 2
    @walkytalky Your final sentence was somewhat obscured by the insult of your first. As it happens, I had the complete working solution written after test #2; I added the remaining tests so readers would have no doubt of the correctness. It took about 30 seconds and I don't consider the time wasted. – Carl Manaster Jun 23 '10 at 13:57
  • 1
    @Carl I certainly apologise for the insult - the sentence was intended lightheartedly, but reads as rude - sorry for that. On the rest we must agree to disagree. – walkytalky Jun 23 '10 at 17:08
  • 9
    What the hell, people? This is clear and well tested code, and the only reason it looks like a lot is because it includes the tests. A+++, would upvote again. – Christoffer Hammarström Dec 19 '10 at 21:59
  • While you are at it make the tests generic too ... but this looks more like stuff which could be useful in a boolean tool library – Christophe Roussy May 21 '13 at 09:43
24

Sum it up. It's called boolean algebra for a reason:

  0 x 0 = 0
  1 x 0 = 0
  1 x 1 = 1

  0 + 0 = 0
  1 + 0 = 1
  1 + 1 = 0 (+ carry)

If you look at the truth tables there, you can see that multiplication is boolean and, and simply addition is xor.

To answer your question:

return (a + b + c) >= 2
memet
  • 73
  • 1
  • 5
15
boolean atLeastTwo(boolean a, boolean b, boolean c) 
{
  return ((a && b) || (b && c) || (a && c));
}
malu
  • 61
  • 1
  • 6
15

It really depends what you mean by "improved":

Clearer?

boolean twoOrMoreAreTrue(boolean a, boolean b, boolean c)
{
    return (a && b) || (a && c) || (b && c);
}

Terser?

boolean moreThanTwo(boolean a, boolean b, boolean c)
{
    return a == b ? a : c;
}

More general?

boolean moreThanXTrue(int x, boolean[] bs)
{
    int count = 0;

    for(boolean b : bs)
    {
        count += b ? 1 : 0;

        if(count > x) return true;
    }

    return false;
}

More scalable?

boolean moreThanXTrue(int x, boolean[] bs)
{
    int count = 0;

    for(int i < 0; i < bs.length; i++)
    {
        count += bs[i] ? 1 : 0;

        if(count > x) return true;

        int needed = x - count;
        int remaining = bs.length - i;

        if(needed >= remaining) return false;
    }

    return false;
}

Faster?

// Only profiling can answer this.

Which one is "improved" depends heavily on the situation.

kerkeslager
  • 1,364
  • 4
  • 17
  • 34
14

Here's another implementation using map/reduce. This scales well to billions of booleans© in a distributed environment. Using MongoDB:

Creating a database values of booleans:

db.values.insert({value: true});
db.values.insert({value: false});
db.values.insert({value: true});

Creating the map, reduce functions:

Edit: I like CurtainDog's answer about having map/reduce apply to generic lists, so here goes a map function which takes a callback that determines whether a value should be counted or not.

var mapper = function(shouldInclude) {
    return function() {
        emit(null, shouldInclude(this) ? 1 : 0);
    };
}

var reducer = function(key, values) {
    var sum = 0;
    for(var i = 0; i < values.length; i++) {
        sum += values[i];
    }
    return sum;
}

Running map/reduce:

var result = db.values.mapReduce(mapper(isTrue), reducer).result;

containsMinimum(2, result); // true
containsMinimum(1, result); // false


function isTrue(object) {
    return object.value == true;
}

function containsMinimum(count, resultDoc) {
    var record = db[resultDoc].find().next();
    return record.value >= count;
}
Community
  • 1
  • 1
Anurag
  • 140,337
  • 36
  • 221
  • 257
  • @Anurag: as much as I love M/R and the exposure that Google recently gave to it (even if it's not the one true M/R from FP), I'd tend to call bullsh!t on your answer. There are billions and billions of lines of code performing Real-World [TM] "stuff" where there ain't a single line of map/reduce used. Someone answering such a question with *this* is definitely flagged in my book as: *"trying to play the smartie"*. Not to mention most interviewers wouldn't be able to tell if you're trying to bullsh!t them or not because they actually never wrote a single program using M/R in their career. – SyntaxT3rr0r Sep 08 '11 at 12:41
  • 2
    @Syntax - Everyone is entitled to their opinion. My answer is just one more approach of looking at the problem. Sure, it sounds exaggerated for 3 booleans values, but that doesn't mean I'm trying to be the smarty-pants here. This is a common approach to problem solving that everyone uses - break the problem down into small pieces. That's how mathematical induction works, that's how most recursive algorithms work, and that's how people solve problems in general. – Anurag Sep 08 '11 at 23:52
13

Taking the answers (so far) here:

public class X
{
    static boolean a(final boolean a, final boolean b, final boolean c)
    {
    return ((a && b) || (b && c) || (a && c));
    }

    static boolean b(final boolean a, final boolean b, final boolean c)
    {
    return a ? (b || c) : (b && c);
    }

    static boolean c(final boolean a, final boolean b, final boolean c)
    {
    return ((a & b) | (b & c) | (c & a));
    }

    static boolean d(final boolean a, final boolean b, final boolean c)
    {
    return ((a?1:0)+(b?1:0)+(c?1:0) >= 2);
    }
}

and running them through the decompiler (javap -c X > results.txt):

Compiled from "X.java"
public class X extends java.lang.Object{
public X();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

static boolean a(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   ifeq    8
   4:   iload_1
   5:   ifne    24
   8:   iload_1
   9:   ifeq    16
   12:  iload_2
   13:  ifne    24
   16:  iload_0
   17:  ifeq    28
   20:  iload_2
   21:  ifeq    28
   24:  iconst_1
   25:  goto    29
   28:  iconst_0
   29:  ireturn

static boolean b(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   ifeq    20
   4:   iload_1
   5:   ifne    12
   8:   iload_2
   9:   ifeq    16
   12:  iconst_1
   13:  goto    33
   16:  iconst_0
   17:  goto    33
   20:  iload_1
   21:  ifeq    32
   24:  iload_2
   25:  ifeq    32
   28:  iconst_1
   29:  goto    33
   32:  iconst_0
   33:  ireturn

static boolean c(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   iload_1
   2:   iand
   3:   iload_1
   4:   iload_2
   5:   iand
   6:   ior
   7:   iload_2
   8:   iload_0
   9:   iand
   10:  ior
   11:  ireturn

static boolean d(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   ifeq    8
   4:   iconst_1
   5:   goto    9
   8:   iconst_0
   9:   iload_1
   10:  ifeq    17
   13:  iconst_1
   14:  goto    18
   17:  iconst_0
   18:  iadd
   19:  iload_2
   20:  ifeq    27
   23:  iconst_1
   24:  goto    28
   27:  iconst_0
   28:  iadd
   29:  iconst_2
   30:  if_icmplt   37
   33:  iconst_1
   34:  goto    38
   37:  iconst_0
   38:  ireturn
}

You can see that the ?: ones are slightly better then the fixed up version of your original. The one that is the best is the one that avoids branching altogether. That is good from the point of view of fewer instructions (in most cases) and better for branch prediction parts of the CPU, since a wrong guess in the branch prediction can cause CPU stalling.

I'd say the most efficient one is the one from moonshadow overall. It uses the fewest instructions on average and reduces the chance for pipeline stalls in the CPU.

To be 100% sure you would need to find out the cost (in CPU cycles) for each instruction, which, unfortunately isn't readily available (you would have to look at the source for hotspot and then the CPU vendors specs for the time taken for each generated instruction).

See the updated answer by Rotsor for a runtime analysis of the code.

TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • 5
    You're only looking at the bytecode. For all you know, the JIT will take a version with branches in the bytecode and turn it into a version with no branches in native code. But one would tend to think that fewer branches in the bytecode would be better. – David Conrad May 30 '12 at 00:18
13

Another example of direct code:

int  n = 0;
if (a) n++;
if (b) n++;
if (c) n++;
return (n >= 2);

It's not the most succinct code, obviously.

Addendum

Another (slightly optimized) version of this:

int  n = -2;
if (a) n++;
if (b) n++;
if (c) n++;
return (n >= 0);

This might run slightly faster, assuming that the comparison against 0 will use faster (or perhaps less) code than the comparison against 2.

David R Tribble
  • 11,918
  • 5
  • 42
  • 52
  • +1 @Loadmaster, I'm sorry but you're wrong! This is the most succinct answer here. (i.e. briefly AND clearly expressed) ;) – Ash Jul 19 '10 at 13:21
  • Micro-optimisation: `++n` is faster than `n++` [because you have to create another copy before doing the increment](http://stackoverflow.com/questions/3181211/prefix-postfix-increment-operators). – M. Mimpen Jan 20 '14 at 13:55
  • @M.Mimpen: Only for class objects. For primitive types (like `n` above), any decent compiler will compile each `++` operation down into a single CPU instruction, whether it's pre or post. – David R Tribble Jan 22 '14 at 23:40
12

The most obvious set of improvements are:

// There is no point in an else if you already returned.
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a && b) || (b && c) || (a && c)) {
        return true;
    }
    return false;
}

and then

// There is no point in an if(true) return true otherwise return false.
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return ((a && b) || (b && c) || (a && c));
}

But those improvements are minor.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
TofuBeer
  • 60,850
  • 18
  • 118
  • 163
12

Yet another way to do this but not a very good one:

return (Boolean.valueOf(a).hashCode() + Boolean.valueOf(b).hashCode() + Boolean.valueOf(c).hashCode()) < 3705);

The Boolean hashcode values are fixed at 1231 for true and 1237 for false so could equally have used <= 3699

barrowc
  • 10,444
  • 1
  • 40
  • 53
9

I don't like ternary (return a ? (b || c) : (b && c); from the top answer), and I don't think I've seen anyone mention it. It is written like this:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if (a) {
        return b||c;
    } 
    else {
        return b&&C;
    }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Roman A. Taycher
  • 18,619
  • 19
  • 86
  • 141
8

In Clojure:

(defn at-least [n & bools]
  (>= (count (filter true? bools)) n)

Usage:

(at-least 2 true false true)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vagif Verdi
  • 4,816
  • 1
  • 26
  • 31
7

I don't think I've seen this solution yet:

boolean atLeast(int howMany, boolean[] boolValues) {
  // check params for valid values

  int counter = 0;
  for (boolean b : boolValues) {
    if (b) {
      counter++;

      if (counter == howMany) {
        return true;
      }
    }
  }
  return false;
}

Its advantage is that once it reaches the number that you're looking for, it breaks. So if this was "at least 2 out of this 1,000,000 values are true" where the first two are actually true, then it should go faster than some of the more "normal" solutions.

Joe Enos
  • 39,478
  • 11
  • 80
  • 136
  • That should probably be: if (++counter == howMany) instead of incrementing and then checking separately. – Joe Enos Jun 21 '10 at 22:55
  • 2
    Or even shorter: if (b && (++counter == howMany)) – Joe Enos Jun 21 '10 at 22:56
  • 1
    I'd do `boolean ... boolValues` so it's easier to call, but still takes an array – Stephen Jun 21 '10 at 23:15
  • I'm not up to date on my Java - didn't know that existed. Kind of a strange syntax, but it's useful - every once in a while I'll do that in C# (params keyword), and it does make things nicer to call. Or, I don't know about Java, but in .NET, arrays and all collections implement IEnumerable, so I'd probably use whatever Java's equivalent is. – Joe Enos Jun 21 '10 at 23:44
  • How does the performance of this compare against the 2of3 example? return a ? (b || c) : (b && c); – Iain Sproat Jun 24 '10 at 11:54
  • Without actually testing it... If you want 2 out of 3, and know for a fact that you want 2 out of 3, and will never change your mind and want 2 out of 4, and don't mind your code being unreadable, then the a?(b||c):(b&&c) example would definitely save you a microsecond or two. – Joe Enos Jun 24 '10 at 13:57
7

We can convert the bools to integers and perform this easy check:

(int(a) + int(b) + int(c)) >= 2
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
vine'th
  • 4,890
  • 2
  • 27
  • 27
  • I don't understand why this isn't the official answer: it's the most concise, the fastest in execution and the simplest to understand. And in C you don't need to transtype: `a+b+c>=2` – dargaud Dec 14 '21 at 12:30
6

Since it wasn't specified how the code should be improved, I shall endeavour to improve the code by making it more amusing. Here's my solution:

boolean atLeastTwo(boolean t, boolean f, boolean True) {
    boolean False = True;
    if ((t || f) && (True || False)) 
        return "answer" != "42";
    if (t && f) 
        return !"France".contains("Paris");
    if (False == True) 
        return true == false;
    return Math.random() > 0.5;
}

In case anyone's wondering if this code works, here's a simplification using the same logic:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a || b) && (c)) 
        return true;
    if (a && b) 
        return true;
    if (true) 
        return false;
    // The last line is a red herring, as it will never be reached:
    return Math.random() > 0.5; 

}

This can be boiled down further to the following:

return ((a || b) && (c)) || (a && b);

But now it's not funny any more.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bruce Attah
  • 321
  • 2
  • 4
5
Function ReturnTrueIfTwoIsTrue(bool val1, val2, val3))
{
     return (System.Convert.ToInt16(val1) +
             System.Convert.ToInt16(val2) +
             System.Convert.ToInt16(val3)) > 1;
}

Too many ways to do this...

ChrisF
  • 134,786
  • 31
  • 255
  • 325
Duby
  • 31
  • 1
  • 3
    Look more like C#. This should be mentioned as such in the answer since the question is Java-targeted :) – BalusC Jun 21 '10 at 17:41
5

A C solution.

int two(int a, int b, int c) {
  return !a + !b + !c < 2;
}

or you may prefer:

int two(int a, int b, int c) {
  return !!a + !!b + !!c >= 2;
}
Mark Edgar
  • 4,707
  • 2
  • 24
  • 18
Suvega
  • 21
  • 1
5

A literal interpretation will work in all major languages:

return (a ? 1:0) + (b ? 1:0) + (c ? 1:0) >= 2;

But I would probably make it easier for people to read, and expandable to more than three - something that seems to be forgotten by many programmers:

boolean testBooleans(Array bools)
{
     int minTrue = ceil(bools.length * .5);
     int trueCount = 0;

     for(int i = 0; i < bools.length; i++)
     {
          if(bools[i])
          {
               trueCount++;
          }
     }
     return trueCount >= minTrue;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
4

The simplest way (IMO) that is not confusing and easy to read:

// Three booleans, check if two or more are true

return ( a && ( b || c ) ) || ( b && c );
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
abelito
  • 1,094
  • 1
  • 7
  • 18
  • Functionally, it is the same. Syntactically, it makes it easier to read for those unaccustomed to the use of the question mark conditional operator. I am willing to bet more people know how to use AND and OR operators than the number of people who know how to use question mark conditional operators. The original question asks for an "improved answer".. The accepted answer does simplify the answer, but raises a very interesting question of what does one consider improvement. Do you program for universal readability or for simplicity? To me, this is an improvement over the accepted answer :) – abelito Jun 21 '10 at 18:48
  • Personal preferences. For me it's way more easy to understand the cleaner ternary operator than this solution. – nico Jun 21 '10 at 20:00
  • 1
    Ah yeah, I saw this problem and was wondering why no one else mentioned this solution. If you write out the OP's logic as boolean algebra, you get A*B+A*C+B*C, which has five operations. By the associative property, you can write A*(B+C)+B*C, which has four operations. – Vivian River Jun 22 '10 at 16:40
  • It's the same as Jack's answer (Jun. 19th) `(C && (A || B)) || (A && B)` just changed the *variable` names... – user85421 Jun 25 '10 at 11:32
4
return 1 << $a << $b << $c >= 1 << 2;
Kevin
  • 13,044
  • 11
  • 55
  • 76
  • Didn't see Suvega's answer before posing this, pretty much the same thing. – Kevin Jun 21 '10 at 19:59
  • Does this really work? I assume this is PHP, but I don't have access to it, but I'll just ask you: what happens if $a is 0? – Mark Edgar Jun 22 '10 at 11:17
  • @Mark It actually doesn't work if $a is 0. That was an oversight. Thanks for pointing that out. :) – Kevin Jun 22 '10 at 12:47
4

Calculated via a truth table:

return (a & b) | (c & (a ^ b));
Boann
  • 48,794
  • 16
  • 117
  • 146
z-index
  • 409
  • 8
  • 14
4

As an addition to @TofuBeer TofuBeer's excellent post, consider @pdox pdox's answer:

static boolean five(final boolean a, final boolean b, final boolean c)
{
    return a == b ? a : c;
}

Consider also its disassembled version as given by "javap -c":

static boolean five(boolean, boolean, boolean);
  Code:
    0:    iload_0
    1:    iload_1
    2:    if_icmpne    9
    5:    iload_0
    6:    goto    10
    9:    iload_2
   10:    ireturn

pdox's answer compiles to less byte code than any of the previous answers. How does its execution time compare to the others?

one                5242 ms
two                6318 ms
three (moonshadow) 3806 ms
four               7192 ms
five  (pdox)       3650 ms

At least on my computer, pdox's answer is just slightly faster than @moonshadow moonshadow's answer, making pdox's the fastest overall (on my HP/Intel laptop).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Barzee
  • 897
  • 3
  • 15
  • 30
4

Currenty with Java 8, I really prefer something like this:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return Stream.of(a, b, c).filter(active -> active).count() >= 2;
}
coder
  • 71
  • 1
  • 3
  • 8
4

In C:

return !!a + !!b + !!c >= 2;
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
3

This sort of is reading better:

if (a) {
    return b || c;
} 
else {
    return b && c;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matt Billenstein
  • 678
  • 1
  • 4
  • 7
3

FYI, this is just the carry-out bit of a full adder. In hardware, you could use the logical effort to determine the optimal circuit based on the different boolean expressions. I would guess that the traditional XOR solution would take more effort than the less succinct expression that the poster presented.

Ben Manes
  • 9,178
  • 3
  • 35
  • 39
3

In Ruby:

[a, b, c].count { |x| x } >= 2

Which could be run in JRuby on the JavaVM. ;-)

3

My first thought when I saw the question was:

int count=0;
if (a)
    ++count;
if (b)
    ++count;
if (c)
    ++count;
return count>=2;

After seeing other posts, I admit that

return (a?1:0)+(b?1:0)+(c?1:0)>=2;

is much more elegant. I wonder what the relative runtimes are.

In any case, though, I think this sort of solution is much better than a solution of the

return a&b | b&c | a&c;

variety because is is more easily extensible. What if later we add a fourth variable that must be tested? What if the number of variables is determined at runtime, and we are passed an array of booleans of unknown size? A solution that depends on counting is much easier to extend than a solution that depends on listing every possible combination. Also, when listing all possible combinations, I suspect that it is much easier to make a mistake. Like try writing the code for "any 3 of 4" and make sure you neither miss any nor duplicate any. Now try it with "any 5 of 7".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jay
  • 26,876
  • 10
  • 61
  • 112
  • You can push it further: I believe in C you could do return a+b+c>1; – Joan Rieu Jun 28 '10 at 18:45
  • Fififox: True, but the question is tagged "Java", where this would not work. The (a?1:0) solution is the closest Java equivalent to what you are suggesting for C. One could, I am sure, endlessly debate the relative merits. In C you can do easy shortcuts by treating booleans an ints; in Java you are protected from hurting yourself by accidentally treating booleans as ints. – Jay Jul 06 '10 at 16:27
3

He's probably not looking for anything convoluted like bitwise comparison operators (not normally convoluted but with booleans, it's extremely odd to use bitwise operators) or something that is very roundabout like converting to int and summing them up.

The most direct and natural way to solve this is with an expression like this:

a ? (b || c): (b && c)

Put it in a function if you prefer, but it's not very complicated. The solution is logically concise and efficient.

stinky472
  • 6,737
  • 28
  • 27
3

It should be:

(a || b && c) && (b || c && a)

Also, if true is automatically converted to 1 and false to 0:

(a + b*c) * (b + c*a) > 0
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
2

Ternary operators get the nerd juices flowing, but they can be confusing (making code less maintainable, thus increasing the potential for bug injection). Jeff Attwood said it well here:

It's a perfect example of trading off an utterly meaningless one time write-time savings against dozens of read-time comprehension penalties-- It Makes Me Think.

Avoiding ternary operators, I've created the following function:

function atLeastTwoTrue($a, $b, $c) {
        $count = 0;

        if ($a) { $count++; }
        if ($b) { $count++; }
        if ($c) { $count++; }

        if ($count >= 2) {
                return true;
        } else {
                return false;
        }
}

Is this as cool as some of the other solutions? No. Is it easier to understand? Yes. Will that lead to more maintainable, less buggy code? Yes.

Community
  • 1
  • 1
labratmatt
  • 1,821
  • 2
  • 20
  • 21
  • 2
    Why not simply `return ($count >= 2);`? Also it's a duplicate of this answer - http://stackoverflow.com/questions/3076078/check-if-at-least-2-out-of-3-booleans-is-true/3076954#3076954 – ChrisF Jun 21 '10 at 17:21
  • @ChrisF The if () {return bool} is more clear to me. I can see how some think it is too verbose. My solution is very similar to http://stackoverflow.com/questions/3076078/check-if-at-least-2-out-of-3-booleans-is-true/3076954#3076954 but it is more complete and contains some justification (the text about ternary operators being confusing). – labratmatt Jun 21 '10 at 17:56
  • 5
    Personally I find multiple if statements Make Me Think more than ternary operators, since each if statement represents a different possible execution path. A single line, OTOH, will always set the value to the left of the equals sign exactly once, no matter how many ternary operators are used to the right of the equals sign. – Jeremy Friesner Jun 21 '10 at 18:17
  • 4
    I much prefer Ternary operators to multi-line stuff that I replace. I often (in legacy code) take ~10 lines down to one with a ternary. Less text = more code on screen = more context. – Luciano Jun 21 '10 at 21:32
  • 2
    Yeah man... it isn't *just* about being cool. Ternaries are *shorter*. Less to read, less to comprehend. Unless you *really* struggle with them, one little ternary is a lot quicker to understand than the... 8 lines and branching opportunities you have there. – mpen Jun 22 '10 at 05:25
  • This is much harder to understand than a ternary operator. – David Conrad May 30 '12 at 00:24
2

Definitely a question that's more about how you solve problems/think than your actual coding ability.

A slightly terser version could be

return ((a ^ b) && (b ^ c)) ^ b

But like a previous poster said, if I saw this in any code I was working on, someone would be getting an earful. :)

Kintar
  • 71
  • 2
2

If the goal is to return a bitwise two-out-of-three value for three operands, arithmetic and iterative approaches are apt to be relatively ineffective. On many CPU architectures, a good form would be "return ((a | b) & c) | (a & b);". That takes four boolean operations. On single-accumulator machines (common in small embedded systems) that's apt to take a total of seven instructions per byte. The form "return (a & b) | (a & c) | (b & c);" is perhaps nicer looking, but it would require five boolean operations, or nine instructions per byte on a single-accumulator machine.

Incidentally, in CMOS logic, computing "not two out of three" requires twelve transistors (for comparison, an inverter requires two, a two-input NAND or NOR requires four, and a three-input NAND or NOR requires six).

supercat
  • 77,689
  • 9
  • 166
  • 211
2

One thing I haven't seen others point out is that a standard thing to do in the "please write me some code" section of the job interview is to say "Could you improve that?" or "Are you completely happy with that" or "is that as optimized as possible?" when you say you are done. It's possible you heard "how would you improve that" as "this might be improved; how?". In this case changing the if(x) return true; else return false; idiom to just return x is an improvement - but be aware that there are times they just want to see how you react to the question. I have heard that some interviewers will insist there is a flaw in perfect code just to see how you cope with it.

Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
2

The best answer to the question should be "As an employee, it's important I write it so that my meaning is clear while maintaining efficiency where necessary for performance." Here's how I'd write it:

function atLeastTwoAreTrue(a, b, c) {
    return (a && b) || (b && c) || (a && c);
}

In reality, the test is so contrived that writing a method that's the fastest, most cryptic possible is perfect acceptable if you accomodate it with a simple comment. But, in general, in this one-liner world, we need more readable code in this world. :-)

ZaBlanc
  • 4,679
  • 1
  • 35
  • 38
2

In C#, off of the top of my head:

public bool lol(int minTrue, params bool[] bools)
{
    return bools.Count( ( b ) => b ) >= minTrue;
}

should be pretty quick.

A call would look like this:

lol( 2, true, true, false );

This way, you are leaving the rules (two must be true) up to the caller, instead of embedding them in the method.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aaron
  • 9
  • 2
2
int count=0;

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if (a)
        count++;
    if (b)
        count++;
    if (c)
        count++;

    if (count>1)
        return true;
    else
        return false;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
endy
  • 3,872
  • 5
  • 29
  • 43
2

The 2 and 3 in the question posed are decidedly magic-numberish. The 'correct' answer will depend on whether the interviewer was trying to get at your grasp of boolean logic (and I don't think pdox's answer could be bested in this respect) or your understanding of architectural issues.

I'd be inclined to go with a map-reduce solution that will accept any sort of list with any arbitrary condition.

CurtainDog
  • 3,175
  • 21
  • 17
2

I found this solution.

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    bool result = !(a ^ b ^ c) && !(!a & !b & !c) || (a & b & c);
    return result;
}
this. __curious_geek
  • 42,787
  • 22
  • 113
  • 137
2

Let the three boolean values be A,B and C....

You can use a k-MAP and come with a boolean expression ...

In this case boolean expression will be A(B+C) + C

or if((A && (B || C )) || C ) { return true; } else return false;

Egalitarian
  • 2,168
  • 7
  • 24
  • 33
2

The non-reduced solution to this problem is:

a'bc + abc' + abc + ab'c

Reducing using K-Maps, one gets:

bc + ab + ac

One could reduce this further by using exclusive or on the a'bc and abc' minterms and combining the abc and ab'c minterms:

b(a ^ c) + ac
SirensOfTitan
  • 799
  • 1
  • 7
  • 19
2

How about (a||b) && (a||c) - Java, uses three comparisons instead of the OP's six.

Wrong, I should have checked earlier.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
d1val
  • 401
  • 4
  • 4
2

Not in context of performance but good code(extensible and readable code that can be reused)

     static boolean trueBooleans (int howMany,boolean ... bools)
     {
      int total = 0;

      for (boolean b:bools)
        if (b && (++total == howMany)) return true;


      return false;
    }

In my humble opinion when writing Java, easy handling unexpected changes and no duplicated code are more important than concise (domain of script languages) or fast program.

teodozjan
  • 913
  • 10
  • 35
1

How about this one:

(a - b) ? c : a
binary_baba
  • 167
  • 1
  • 8
1

Taking another approach to this using Java 8's Stream functionality, for any number of booleans with an arbitrary required amount. The Stream short circuits if it hits the limit before processing all of the elements:

public static boolean atLeastTrue(int amount, Boolean ... booleans) {
    return Stream.of(booleans).filter(b -> b).limit(amount).count() == amount;
}

public static void main(String[] args){
    System.out.println("1,2: " + atLeastTrue(1, true, false, true));
    System.out.println("1,1: " + atLeastTrue(1, false, true));
    System.out.println("1,0: " + atLeastTrue(1, false));
    System.out.println("1,1: " + atLeastTrue(1, true, false));
    System.out.println("2,3: " + atLeastTrue(2, true, false, true, true));
    System.out.println("3,2: " + atLeastTrue(3, true, false, true, false));
    System.out.println("3,3: " + atLeastTrue(3, true, true, true, false));
}

Output:

1,2: true
1,1: true
1,0: false
1,1: true
2,3: true
3,2: false
3,3: true
mkobit
  • 43,979
  • 12
  • 156
  • 150
1

X = OR(a+b,c)

a b c X

1 1 0 1

0 0 1 1

0 1 1 1

dai
  • 1
  • 1
  • What language is this? What does OR mean? (boolean? bitwise?) What does + mean? (The question is tagged java, where + isn't an operation you can do on booleans and there isn't any "OR" in the language.) – Don Hatch Nov 22 '21 at 19:25
1

C:

if (!!a + !!b + !!c >= 2)
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
1

If I convert the booleans into a number, and if the number is not a power of two, it has at least two trues.

a*4 + b*2 + c*1 = N
return( N != 0 && (N&(N-1)) != 0)

I am just giving an alternative.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kshitij Banerjee
  • 1,678
  • 1
  • 19
  • 35
0
public static boolean atLeast(int atLeastToBeTrue, boolean...bools){
    int booleansTrue = 0;
    for(boolean tmp : bools){
        booleansTrue += tmp ? 1 : 0;
    }
    return booleansTrue >= atLeastToBeTrue;
}

You can choose how many at least you want to be true from varargs a.k.a boolean[] :-)

To Kra
  • 3,344
  • 3
  • 38
  • 45
0
function atLeastTwoTrue($a, $b, $c) {

  int count = 0;
  count = (a ? count + 1 : count);
  count = (b ? count + 1 : count);
  count = (c ? count + 1 : count);
  return (count >= 2);
}
itpatil
  • 11
  • 1
0

It seems to me that three out of three are quite arbitrary numbers, and the function should work with an arbitrary number. So in order to answer the question, I'd write a function that would work out if x in an array were true, for example,

bool istrue ( int x, bool[] list)
    y = count true in list
    return y >= x
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Derek Organ
  • 8,323
  • 17
  • 56
  • 75
0

This is very simple with the help of arithmatic operation.

boolean a = true;
boolean b = false;
boolean c = true;


// Exactly One boolean value true.
if((a?1:0)+(b?1:0)+(c?1:0)==1) 
   return true;
else
   return false;

// Exactly 2 boolean value true.
if((a?1:0)+(b?1:0)+(c?1:0)==2) 
   return true;
else
   return false;

and this is how you can just increase the value of constant to check how many boolean values are true

Dupinder Singh
  • 7,175
  • 6
  • 37
  • 61
0

Its easy with operator overloading if you have a lot of booleans.

operator fun Boolean.unaryPlus() = if (this) 1 else 0
// ...
if(+bool1 + +bool2 + ... + +boolN > 2) {
    // ...
}
Bobin
  • 278
  • 5
  • 15
0

The simplest form using ternary operators to solve the problem is:

return a ? (b ? true : c) : (b ? c : false);

You may also want to invest finding a solution by using double negation of the requirement, meaning to say, instead of at least two true values, you need to satisfy the condition at most one false value.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mdprotacio
  • 842
  • 6
  • 18
0

Function ko returns the answer:

static int ho(bool a)
{
    return a ? 1 : 0;
}

static bool ko(bool a, bool b, bool c)
{
    return ho(a) + ho(b) + ho(c) >= 2 ? true : false;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dhananjay
  • 3,673
  • 2
  • 22
  • 20
  • 2
    There is no need for the ? true : false. That tells the complier, if this is true, return true, but if it is false, return false. Cut out the unnecessary step and just return ho(a) + ho(b) + ho(c) >= 2; – Jacklynn May 20 '14 at 13:14
-1

Another one:

return a? b||c : b&&c
nabil london
  • 511
  • 2
  • 13
  • 1
    Another copy of the accepted answer? It's always a good idea to check first to see if your answer has already been posted by others. – Kal Jun 11 '20 at 05:22
-4

I believe using plain boolean operators (a || b) && (b || c) is fine and is simpler.

You can swap any of the 3 letters with any of the other two and it's still the same expresion.

gnrfan
  • 19,071
  • 1
  • 21
  • 12
-6

I think the simplest solution is:

return (a && b) || c;

user1883212
  • 7,539
  • 11
  • 46
  • 82
-7

My first thought was

return (a||b)&&(b||c)

but for ease of reading I liked the proposed a+b+c>=2 solution that you guys suggested better

Brandon
  • 11
  • 1