Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I have written a method that checks if n number of true booleans are present in a boolean[] array. Then I improved it to var args format which is as follows:

public static boolean checkNTrue(int n, boolean... args) {
    assert args.length > 0;
    int count = 0;
    for( boolean b : args ) {
        if(b)   count++;
        if( count > n )
            return false;
    }
    return ( count == n );
}

I implement it to check if only one of all those booleans is true by using:

boolean result = checkNTrue(1, false, true, false, false);

The above returns true confirming the required case. But what if there are only two boolean arguments? A simple XOR could return the right result.

And in the case of 3 booleans, return (a ^ b ^ c) ^ (a && b && c); works fine too. So, my question is:

Do I need to write separate methods to check in cases with 2 and 3 variables?

Or will this one method do fine? I invite every kind of criticism through downvotes and comments, but please enlighten me! :-)

share|improve this question
2  
Why assert that args.length > 0? If argshas zero length, why not just return n == 0? –  Hurkyl Mar 15 at 3:49
1  
Please don't edit the code in the question in a way that invalidates existing answers. I've rolled it back to Rev 2. –  200_success Mar 23 at 6:21

5 Answers 5

up vote 10 down vote accepted

Premature optimization is a bad idea. Before you try to optimize anything, run a profiler to measure where your bottlenecks are. Unless you are running this function in a tight loop, it's unlikely that this function will be a bottleneck.

The special cases that you would introduce don't come for free:

  • The more line of code you write, the more bugs you are likely to have, statistically.
  • Your unit tests also have to address the special cases.
  • There is a bit of overhead in checking whether your special cases apply.

Taking all that into consideration, it's almost certainly not worthwhile to add special cases.


The assertion assert args.length > 0 might be inappropriate. Considering this code in a vacuum, there is nothing to guarantee that that assertion is logically true. Rather, it's a runtime validation check. Validation failures should throw an IllegalArgumentException. They shouldn't be assertion failures. (Assertions can be disabled, defeating your check.)

If this were a non-public method, and you are sure that you've written your code such that all call sites have at least two arguments, then an assertion might be appropriate.

Here's a philosophical question: should checkNTrue(0) be true or false? I think it should be true.

share|improve this answer
1  
@ambigram_maker You changed the assert to args.length > -1. Is that really useful? Is it even technically possible for the length of an array to become negative? –  RoToRa Mar 17 at 13:27
    
Sorry... Now I understand that the assert is useless. –  ambigram_maker Mar 23 at 6:24
  1. assert statements can be disabled, so I'd throw an exception instead:

    if (args.length < 1) {
        throw new IllegalArgumentException("must have at least one boolean parameter");
    }
    
  2. if(b)   count++;
    

    I'd put the count++ statement to a separate line. From Code Complete, 2nd Edition, p759:

    With statements on their own lines, the code reads from top to bottom, instead of top to bottom and left to right. When you’re looking for a specific line of code, your eye should be able to follow the left margin of the code. It shouldn’t have to dip into each and every line just because a single line might contain two statements.

  3. I'd rename the method to checkExactlyNTrue for easier understanding. (It would have answered my initial question: what does it do if I have more than n true parameters?)

  4. Do I need to write separate methods to check in cases with 2 and 3 variables?

    If you don't have a concrete reason why would you do it? Keep it simple. The method in the question works with two and three parameters too, I would use that.

  5. And in the case of 3 booleans, return (a ^ b ^ c) ^ (a && b && c); works fine too. So, my question is:

    This would be really hard to read and understand, the method in the question expresses the intent/purpose of the method better.

share|improve this answer
1  
According to best practices, all if statements should have braces, and count++ should be on its own line. However, if the author insists on omitting the braces, then treating if (b) count++; as one statement on one line is safer. –  200_success Mar 14 at 16:23
    
I would argue that the check for at least 1 boolean is not needed. The method is still correct without it, no? –  DannyMo Mar 14 at 18:09
    
@DannyMo: Yes, it as far as I see it is. (I didn't want to change the original behaviour.) –  palacsint Mar 14 at 22:16
    
@DannyMo: I'm not checking my method with 1 boolean, but I'm implementing it! That's what I wanted to know... is it Okay if I use it to check only ONE boolean? :-) –  ambigram_maker Mar 15 at 5:33
if(b)   count++;
if( count > n )
    return false;

...can be improved as...

if (b && ++count > n)
    return false;

...which uses "short circuit evaluation" so the stuff after && doesn't run if b if false, i.e. it doesn't bother to check count when it hasn't just been modified. I wouldn't bet on an optimiser understanding this relationship well enough to eliminate the extra check in !b situations.

share|improve this answer
1  
Your observation about efficiency is valid. However, it would be clearer to write it as a nested statement. if (b) { count++; if (count > n) { return false; }} –  200_success Mar 14 at 23:19
    
@200_success: I considered that, but I think programmers reading this should either already know how short-circuit evaluation and pre- vs post-increment work and be entirely comfortable with them, or make the time to learn. :^) This is pretty basic stuff, and if they're not 100% clear, they'll be guessing at what a lot of existing code does. But then I'm a C++ programmer at heart... bread and butter ;-). –  Tony D Mar 14 at 23:38
    
@TonyD: Short-circuit evaluation is great for dealing with cases where the latter tests might give exceptions or undefined behavior should the earlier ones fail... using it to control side effects is rather strange. (shell scripting aside... but then shell scripting is always strange!) If I saw code like that in real life, and noticed the effect, I would be far more likely to think "oh, the author made a mistake" before anything else. –  Hurkyl Mar 15 at 3:54

At the moment, your code is simple enough so that it's quite easy to understand what it does and to be convinced quite easily that is does correctly. One of the main principle of programming is Keep it simple.

Adding special cases will give you more code to maintain and potentially introduce bugs. This is probably not something you want.

If you want to be sure that your function returns the same thing as xor, you might want to use this in your unit test (you were about to add unit tests, weren't you?)

If your reasoning to add special cases was performances, I guess you shouldn't be too worried about that as it corresponds to a situation which would have been super fast anyway.

share|improve this answer
    
Using xor in unit tests reminds me Production Logic in Test –  palacsint Mar 14 at 16:10

If you really want this to be fast — like smokingly, freakingly, astonishingly fast — then throw everything out that you've go so far and rewrite the whole thing to be an O(1) implementation instead of an O(n) implementation.

Always remember the first rule of optimization: The fastest way to do something is to not do it. And the thing you want to avoid here is looping through the array to count values. Memory accesses are expensive, especially if they result in L1 or L2 cache misses or VM page faults.

So here's what I would do: Create a wrapper class for the boolean array. Provide read and write methods for accessing elements of the array. Maintain a count c of true values. When an element is set (e.g., true or false value being stored at some index), compare the new value against the old value. If the value is transitioning from false to true, increment c by 1; if the value is transitioning from true to false, decrement c by 1. Then, in the method which checks if n true boolean values are present, simply compare n to c and you're done. Extremely minimal overhead, and extremely fast checking with no looping.

share|improve this answer
1  
I think you've just described Bitset.cardinality() (assuming it is efficiently implemented). –  200_success Mar 15 at 7:41
    
Yes, I understand that storing the required values on creation is definitely faster... but I'm applying this in a static method, so I don't know how much practical it would be. Would'nt using a wrapper add additional overhead every time I call it? –  ambigram_maker Mar 16 at 14:41
    
@ambigram_maker — Using a wrapper class would add additional overhead, yes. If you are doing tons of updates and relatively few counting queries, then it may not be worth it; but if you are doing relatively few updates and tons of counting queries, then it will pay for itself easily — especially if there are millions of elements. It's hard to know which way would be best without knowing more about the problem domain... but you may find that the overhead is minimal anyway. –  Todd Lehman Mar 16 at 16:09

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.