Check if at least two out of three booleans are true
Asked Answered
S

65

615

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?

Sigman answered 19/6, 2010 at 15:46 Comment(19)
Inline the return statement.Consolation
atLeastTwo(iWantYou, iNeedYou, imEverGonnaLoveYou)Fraenum
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?Contretemps
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).Keystone
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.Juba
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.Hanschen
@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.Briones
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.Creak
return true; //math joke : if vs if and only ifPlectrum
Why do people upvote the most trivial questions?Boyar
Seriously, how does this get 78 upvotes?Versed
Questions that are general and easy to understand get a lot of up votes. Questions that are very specific and technical don't.Sven
Should a separate question be asked about how you'd do this in your favorite language, and non-java answers moved there?Fraenum
Not only upvoting, but people are even marking it as a favourite (47 favourites now). Woow.Tucky
@BlueRaja-DannyPflughoeft the simple questions get upvoted, because everyone understands them, and this question actually got a few good answers as well.Shantelleshantha
125 interviewers have favorited this question. And they will get what they deserve ;)Fredric
you can write a method as getTrueValuesSize(boolean[] values) { List<Boolean> 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.Brandybrandyn
@BlueRaja-DannyPflughoeft, en.wikipedia.org/wiki/Parkinson's_law_of_trivialityTurki
It depends on what "improve" means here, readability or performance.Jarrettjarrid
B
848

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

Brokendown answered 19/6, 2010 at 15:46 Comment(16)
+1: lovely solution to the puzzle, but hopefully we don't see anything like this in the real world :)Doran
@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.Totalizer
I love how every other answer is trying to optimize, while that's obviously not what the interviewer wanted to hear.Rozalie
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.Keystone
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.Jeanmariejeanna
@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.Brokendown
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.Rapparee
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.Gullet
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.Guyguyana
So elegant. I must admire the beauty for a while longer. I will sit here and bask in it until my boss comes by.Immemorial
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?Immemorial
@MattC: No. You're not reading it correctly. But imagine that it did return true in both scenarios: what would that be equivalent to?Robbinrobbins
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.Slovak
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.Osteomalacia
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.Receiptor
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.Anthropography
T
510

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

return a ^ b ? c : a
Tiffanietiffanle answered 19/6, 2010 at 15:46 Comment(13)
Wow, cool solution. But for me its inverted version is easier to understand: a==b ? a : cWyeth
Yeah, that's definitely more clear for anyone who has to read the code. Heh, admittedly I'd probably do a quick double-take at what I wrote if I saw it somewhere else.Tiffanietiffanle
a ^ b ? c : a ^ b ? c : a ^ b ? c : aDehlia
Yay,..XOR gets such a bad press and you seldom get the chance to use it.Lorica
@Stimul8d maybe because, for booleans, it's the same as != but less readable? Figuring that out was a eureka moment for me...Incunabulum
Does it do (a ^ b) ? c : a OR a ^ (b ? c : a)Falcate
@Falcate The first one. XOR has a higher precedence than the ternary operator.Tiffanietiffanle
The a ^ b is throwing me off - what exactly is going on?Libation
@DoctorOreo a ^ b is the same as a != b in this case, so if at least two are true a must not equal b (i.e one of them is true) and c must be true, otherwise a must equal b and a must be true.Tiffanietiffanle
I prefer the purely binary form: return ((a^b) & c) | (a & b). It is branch-less (faster) and easy to read : (a or b is true and c is true) or (a and b are both true). Note that (a|b) and (a^b) both work with this formula.Ko
unfortunately I am just allowed to upvote once :( ..simple and accurate. great answer!Preglacial
What does the ? operator do? What does the : operator do?Phototelegraph
@AaronFranke It's the ternary operatorTiffanietiffanle
W
228

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
Wyeth answered 19/6, 2010 at 15:46 Comment(20)
a+b+c >= 2 : this doesn't work with negatives, right? You may have to do the !!a thing, I'm not sure.Brokendown
<s>-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).</s> Actually I guess C99 includes in its standard that true is defined as 1. But I still wouldn't do this.Hexamerous
Is that possible if your input is result of boolean operations? And is that possible for "bool" type in C++?Wyeth
@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.Hexamerous
unexpected... and happy to be wrong... updating my answer slightlyNaker
Actually, I didn't expect it too. I thought that straightforward ab|bc|ac would be unbeatable.Wyeth
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.Wyeth
Be cautious with microbenchmarks: java.sun.com/docs/hotspot/HotSpotFAQ.html#benchmarking_simpleAbrahamsen
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.Wyeth
Obviously, these results suggest you should use the DEAD method.Ynes
What does the !! do? Does that NOT NOT, or basically true->false->true?Adolpho
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...Mcloughlin
@Mcloughlin 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. :)Wyeth
@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) == 1Hexamerous
@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.Sven
a + b + c <= 2 can be improved even further to (a + b + c) >> 1Daw
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!Kerwinn
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-11A511Shantelleshantha
What does the ? operator do? What does the : operator do?Phototelegraph
These can only be used together and therefore they don't count as individual operators, but rather as one ternary operator. The informal meaning of A ? B : C is "if A then B else C".Wyeth
G
162
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.

Garrote answered 19/6, 2010 at 15:46 Comment(4)
c is never even tested... brilliant!Foolscap
Uses transitive relation of equality and the fact that a boolean is either true or false +1Puglia
So elegant! I had to check with pen and paper to believe it:) Kudos to you sir!Floatable
I think about this as "if a and b agree, they have the majority vote, so go with whatever it is, else, they disagree, so c is the deciding vote"Broussard
E
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
Eyesight answered 19/6, 2010 at 15:46 Comment(3)
@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.Triangular
+1 for something new. My next functional spec will include a K-map, whether it needs it or it.Ungenerous
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.Bodycheck
C
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;
Colorfast answered 19/6, 2010 at 15:46 Comment(4)
I agree with the premise, but (a && b) || (b && c) || (a && c) is much more readable than your solution IMHO.Triparted
Hmm, now I need a "two out of FOUR booleans" version... danatel's version is much easier now.Tarnation
Or in Scala: Seq(true, true, false).map(if (_) 1 else 0).sum >= 2Misstep
@retronym: Hmm, no. The Java way works just fine in Scala and is both more readable and more efficient.Brunn
M
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.

Masoretic answered 19/6, 2010 at 15:46 Comment(7)
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.Hexamerous
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.Bowing
@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.Deranged
@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.Hexamerous
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.Naker
@Peter Tillemans There is no mixing with binary operators, in Java these are boolean operators.Id
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.Ko
C
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;
    }
}
Ceiba answered 19/6, 2010 at 15:46 Comment(14)
Wow, I've never seen a fully tested method before seeing this one.Wyeth
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.Berserker
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().Ceiba
@Carl - your code is spending a lot of time creating temporary boolean arrays. Very strange for profiling performance.Bus
@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.Wearproof
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.Aeriform
@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.Ceiba
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.)Robbinrobbins
@Robbinrobbins 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.Ceiba
@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?Robbinrobbins
@Robbinrobbins 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.Ceiba
@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.Robbinrobbins
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.Madelinemadella
While you are at it make the tests generic too ... but this looks more like stuff which could be useful in a boolean tool libraryPuglia
S
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
Seductress answered 19/6, 2010 at 15:46 Comment(5)
This is the most elegant solution, in my opinion.Barbaric
Rookie mistake though, a boolean value is NOT 0, that does not mean its always 1.Ovarian
Except that the tag on the post says "Java", and you can't write "a+b+c" when they are defined as booleans in Java.Sven
To work in Java, it would have to be return ((a?1:0) + (b?1:0) + (c?1:0)) >= 2.Orourke
Duh, I voted this up because I thought it was a C++ question... why am I reading java questions? :/Tova
B
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.

Brandtr answered 19/6, 2010 at 15:46 Comment(0)
M
15
boolean atLeastTwo(boolean a, boolean b, boolean c) 
{
  return ((a && b) || (b && c) || (a && c));
}
Marrow answered 19/6, 2010 at 15:46 Comment(0)
P
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;
}
Photic answered 19/6, 2010 at 15:46 Comment(2)
@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.Carnage
@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.Photic
O
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.

Orourke answered 19/6, 2010 at 15:46 Comment(3)
+1 @Loadmaster, I'm sorry but you're wrong! This is the most succinct answer here. (i.e. briefly AND clearly expressed) ;)Juba
Micro-optimisation: ++n is faster than n++ because you have to create another copy before doing the increment.Vania
@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.Orourke
N
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.

Naker answered 19/6, 2010 at 15:46 Comment(1)
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.Puissance
K
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

Kangaroo answered 19/6, 2010 at 15:46 Comment(1)
or (a?1:0)+(b?1:0)+(c?1:0) >= 2Storey
N
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.

Naker answered 19/6, 2010 at 15:46 Comment(0)
C
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;
    }
Canossa answered 19/6, 2010 at 15:46 Comment(0)
O
8

In Clojure:

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

Usage:

(at-least 2 true false true)
Outturn answered 19/6, 2010 at 15:46 Comment(1)
+1 Great generic version shows the power of the Lisps. Thanks,Peper
G
7

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

(int(a) + int(b) + int(c)) >= 2
Ginkgo answered 19/6, 2010 at 15:46 Comment(1)
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>=2Primacy
I
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.

Izzard answered 19/6, 2010 at 15:46 Comment(6)
That should probably be: if (++counter == howMany) instead of incrementing and then checking separately.Izzard
Or even shorter: if (b && (++counter == howMany))Izzard
I'd do boolean ... boolValues so it's easier to call, but still takes an arrayFears
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<T>, so I'd probably use whatever Java's equivalent is.Izzard
How does the performance of this compare against the 2of3 example? return a ? (b || c) : (b && c);Clothesline
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.Izzard
E
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.

Existential answered 19/6, 2010 at 15:46 Comment(0)
G
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;
}
Gerhardt answered 19/6, 2010 at 15:46 Comment(0)
U
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;
}
Upshaw answered 19/6, 2010 at 15:46 Comment(0)
H
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...

Heda answered 19/6, 2010 at 15:46 Comment(1)
Look more like C#. This should be mentioned as such in the answer since the question is Java-targeted :)Abrahamsen
O
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;
}
Orton answered 19/6, 2010 at 15:46 Comment(3)
Instead of Arrays.asList(a, b, c).stream(), you can have Stream.of(a, b, c)...Schear
Very heavyweight.Garrote
@Boan I think is more important the code reveals intention than early optimizations...Orton
R
4

In C:

return !!a + !!b + !!c >= 2;
Reciprocation answered 19/6, 2010 at 15:46 Comment(4)
Actually, this answer is wrong… it should be >= 2, since you need at least two true booleans, not exactly two.Shantelleshantha
@Paul Wagland: Thanks for the catch.Reciprocation
@ergosys: Wth I answered twice?Reciprocation
Nice one. I'd prefer this one since it will allow you to expand it to "three out of four" etc. Wondering if there is a caveat to counting the number of true's and comparing that to the amount though.Noto
T
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).

Thedathedric answered 19/6, 2010 at 15:46 Comment(0)
C
4

Calculated via a truth table:

return (a & b) | (c & (a ^ b));
Chink answered 19/6, 2010 at 15:46 Comment(1)
Well, the original solution is easier.Chink
B
4
return 1 << $a << $b << $c >= 1 << 2;
Buckram answered 19/6, 2010 at 15:46 Comment(3)
Didn't see Suvega's answer before posing this, pretty much the same thing.Buckram
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?Upshaw
@Mark It actually doesn't work if $a is 0. That was an oversight. Thanks for pointing that out. :)Buckram
B
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 );
Bridgettebridgewater answered 19/6, 2010 at 15:46 Comment(4)
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 :)Bridgettebridgewater
Personal preferences. For me it's way more easy to understand the cleaner ternary operator than this solution.Hindu
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 AB+AC+BC, which has five operations. By the associative property, you can write A*(B+C)+BC, which has four operations.Rotherham
It's the same as Jack's answer (Jun. 19th) (C && (A || B)) || (A && B) just changed the *variable` names...Twelvemo
N
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
Nefen answered 19/6, 2010 at 15:46 Comment(0)
M
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.

Marybelle answered 19/6, 2010 at 15:46 Comment(0)
S
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".

Sven answered 19/6, 2010 at 15:46 Comment(2)
You can push it further: I believe in C you could do return a+b+c>1;Preponderance
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.Sven
S
3

In Ruby:

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

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

Snowbird answered 19/6, 2010 at 15:46 Comment(0)
O
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.

Obsequious answered 19/6, 2010 at 15:46 Comment(0)
L
3

This sort of is reading better:

if (a) {
    return b || c;
} 
else {
    return b && c;
}
Listed answered 19/6, 2010 at 15:46 Comment(0)
D
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.

Dunlap answered 19/6, 2010 at 15:46 Comment(0)
D
2

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

Wrong, I should have checked earlier.

Dalliance answered 19/6, 2010 at 15:46 Comment(1)
This one is wrong.It fails if a is true and b and c are false.Corrosion
I
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
Ireneirenic answered 19/6, 2010 at 15:46 Comment(0)
A
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

return (A && (B || C )) || C;
Assimilative answered 19/6, 2010 at 15:46 Comment(2)
Doesn't this return true with just C been true?Lugar
oops ... i forgot to add something... its if((A && (B || C )) || (B && C) { return true; } else return false;Assimilative
D
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;
}
Doyledoyley answered 19/6, 2010 at 15:46 Comment(0)
F
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.

Foolscap answered 19/6, 2010 at 15:46 Comment(0)
C
2
int count = 0;

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

    return count > 1;
}
Chavis answered 19/6, 2010 at 15:46 Comment(0)
W
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.

Washable answered 19/6, 2010 at 15:46 Comment(0)
M
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. :-)

Mercer answered 19/6, 2010 at 15:46 Comment(0)
A
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.

Armindaarming answered 19/6, 2010 at 15:46 Comment(0)
T
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).

Tackling answered 19/6, 2010 at 15:46 Comment(0)
F
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. :)

Featurelength answered 19/6, 2010 at 15:46 Comment(0)
J
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++; }

    return $count >= 2;
}

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.

Johppa answered 19/6, 2010 at 15:46 Comment(6)
Why not simply return ($count >= 2);? Also it's a duplicate of this answer - #3076578Quadruped
@Quadruped 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 #3076578 but it is more complete and contains some justification (the text about ternary operators being confusing).Johppa
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.Signification
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.Chandelle
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.Adamek
This is much harder to understand than a ternary operator.Puissance
B
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
Beaded answered 19/6, 2010 at 15:46 Comment(0)
C
1

How about this one:

(a - b) ? c : a
Commence answered 19/6, 2010 at 15:46 Comment(1)
a != b ? c : a seems more intuitive.Tova
A
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.

Analects answered 19/6, 2010 at 15:46 Comment(0)
R
1

C:

if (!!a + !!b + !!c >= 2)
Reciprocation answered 19/6, 2010 at 15:46 Comment(0)
H
1

X = OR(a+b,c)

a b c X

1 1 0 1

0 0 1 1

0 1 1 1

Hatbox answered 19/6, 2010 at 15:46 Comment(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.)Congratulant
F
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) {
    // ...
}
Ford answered 19/6, 2010 at 15:46 Comment(0)
F
0

This is very simple with the help of arithmetic operation.

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

// Exactly one boolean value true.
return (a?1:0)+(b?1:0)+(c?1:0)==1;

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

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

Froe answered 19/6, 2010 at 15:46 Comment(0)
Y
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[] :-)

Yser answered 19/6, 2010 at 15:46 Comment(0)
L
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;
}
Leekgreen answered 19/6, 2010 at 15:46 Comment(1)
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;Orpah
O
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.

Ocko answered 19/6, 2010 at 15:46 Comment(1)
looks a lot like a ? b||c : b&&cCongratulant
M
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
Moskowitz answered 19/6, 2010 at 15:46 Comment(0)
C
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);
}
Caput answered 19/6, 2010 at 15:46 Comment(1)
Gahh... why?! The other counting methods already posted are so much better!Adamek
C
-1

Another one:

return a? b||c : b&&c
Cousteau answered 19/6, 2010 at 15:46 Comment(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.Kemerovo
E
-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.

Ergener answered 19/6, 2010 at 15:46 Comment(2)
except this answer is wrong. it would return true if only b is trueBuckram
You're right. So I stick to a+b+c>=2 then. Works for PHP and Python too.Ergener
B
-6

I think the simplest solution is:

return (a && b) || c;
Belinda answered 19/6, 2010 at 15:46 Comment(1)
This only checks if both a and b is true or if c is trueRepeated
H
-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

Humble answered 19/6, 2010 at 15:46 Comment(1)
Your answer returns an incorrect value when a and c are false, and only b is true.Furmark

© 2022 - 2024 — McMap. All rights reserved.