How do you make a conditional statement return true when only one condition is true?

Viewed 963

I need to implement a functionality that takes a list of boolean values as input and returns true only if one of the conditions is true (if more, returns false). More formally, f(c1, c2, c3 ... cN) returns true if and only if there's only one condition that evaluates true, otherwise it returns false.

I implemented this method,

boolean trueOnce(boolean[] conditions) {
    boolean retval = false;
    for (boolean c: conditions) {
        if (c) {
            if (!retval) {
                retval = true;
            } else {
                retval = false;
                break;
            }
        }
    }
    return retval;
}

but I'm asking for something more practical. I'm working with Java, but I think this problem is universal for every language. Thanks.

EDIT: The above example does the job very well, I'm only asking for a more practical way.

5 Answers

A simple loop with a condition counting the true presence is a simple way to go The return statement is a comparison returning a boolean, whether the true count is qual exactly to 1:

long count = 0;
for (boolean condition: conditions) {
    if (condition) {
        count++;
    }
}
return count == 1;

This always iterates all the array which is not always necessary. You can optimize the iteration to stop when there are two true values found, hence it doesn't make sense to continue the iteration.

long count = 0;
for (boolean condition: conditions) {
    if (condition && ++count > 1) {
        break;
    }
}
return count == 1;

you could use this solution

public boolean trueOnce(boolean[] conditions) {
         boolean m = false;
         for(boolean condition : conditions) {
             if(m && condition)
                 return false;
             m |= condition;
         }
         return m;
     }

this is a very small solution that does exactly what you want in very few lines.

Using Java Stream API:

boolean trueOnce(boolean[] conditions) {
    return IntStream.range(0, conditions.length)
        .filter(x -> conditions[x])  // leave only `true` values
        .limit(2)             // no need to get more than two
        .count() == 1;        // check if there is only one `true` value
}

Using Stream API, you could rewrite it as (though it looks less "practical" as plain loop):

import java.util.stream.*;

static boolean trueOnce(boolean ... conditions) {
    // find index of first true, if not available get -1
    int firstTrue = IntStream.range(0, conditions.length)
                             .filter(i -> conditions[i])
                             .findFirst().orElse(-1);

    // if first true is found, check if none in the remainder of array is true
    return firstTrue > -1 && IntStream.range(firstTrue + 1, conditions.length)
                                      .noneMatch(i -> conditions[i]);
}

Restoring initial version with a change suggested by @VLAZ:

import java.util.stream.*;

boolean trueOnce(boolean[] conditions) {
    return IntStream.range(0, conditions.length)
                    .filter(i -> conditions[i])
                    .limit(2) // !
                    .count() == 1;
}

An iteration can be performed using the while operator. A variable is defined to control the increments of positive values and another to evaluate each element of the array. These two variables will be our stop conditions and the method will return the solution, true for when there is a single positive value and false in all other cases.

boolean trueOnce(boolean[] conditions) 
    {
        int i = 0, count = 0;
        
        while(count <= 1 && i < conditions.length){
            if(conditions[i++]){
                count++;
            }
        }
        
        return count == 1;
    }

or following the suggestion, we can use:

private static boolean trueOnce(boolean[] conditions) 
{
    int count = 0;
    
    for(int i = 0; i < conditions.length && count <= 1; i++){
        if(conditions[i]){
            count++;
        }
    }
    
    return count == 1;
}
Related