当只有一个条件为真时,如何使条件语句返回true?

3

我需要实现一个功能,它将布尔值列表作为输入,并仅在其中一个条件为真时返回true(如果有更多,则返回false)。 更正式地说,f(c1,c2,c3 ... cN) 仅在只有一个条件为 true 时返回true,否则返回false。

我已经实现了这个方法,

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

但我希望得到更实用的解决方案。我正在使用Java,但我认为这个问题对于每种编程语言都是普遍存在的。谢谢。

编辑:上面的示例已经很好地完成了工作,我只是在寻求一种更实用的方式。


for (boolean condition : conditions) if (condition) return true对于(布尔条件:条件),如果(条件)则返回真。 - Zinc
1
抱歉,我没有仔细阅读你的问题。您只需计算真实条件的数量,并返回nbTrue == 1吗? - Zinc
@kafjagjys,你的代码看起来相当不错。 - Nowhere Man
1
你会认为哪种解决方案更“实用”? - Slaw
5个回答

3
一个简单的循环带有一个条件,计算 true 的出现次数是一个简单的方法。返回语句是一个比较,返回一个布尔值,即 true 的计数是否恰好等于 1:
long count = 0;
for (boolean condition: conditions) {
    if (condition) {
        count++;
    }
}
return count == 1;

这总是遍历整个数组,这并不总是必要的。您可以通过在找到两个true值时停止迭代来优化迭代,因此继续迭代没有意义。

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

“需要遍历整个数组” - 只有在最坏的情况下才是真的(即最后一个元素是第一个或第二个真值)。根据要求,算法可以在遇到第二个真值后立即短路。 - Slaw
@Slaw,算法如何“在遇到第二个真值后立即短路”? - RIVERMAN2010
@RIVERMAN2010,要求是如果真值的数量为0> 1,则最终结果为false。没有必要检查超过2个真值,因为此时您已经知道最终结果为false - Slaw
@Slaw: 是的,你说得对。我已经修复了我的错误并添加了一个优化。 - Nikolas Charalambidis
1
顺便问一下,为什么要使用 long 来计数? - Nowhere Man
@AlexRudenko 为什么不呢 :) 如果你问我“为什么不用int”,我会回答你“为什么不用short?”这取决于情况... - Nikolas Charalambidis

3
您可以使用这个解决方案。
public boolean trueOnce(boolean[] conditions) {
         boolean m = false;
         for(boolean condition : conditions) {
             if(m && condition)
                 return false;
             m |= condition;
         }
         return m;
     }

这是一个非常小的解决方案,只用几行代码就能完全满足你的需求。


2
不是百分之百确定,但我认为三元运算符可以简化为 m |= condition - Slaw
@Slaw 是的,你说得对,它可以简化,我会编辑我的答案。 - RIVERMAN2010

3

使用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
}

在许多方面都是错误的!如果根本无法编译,那它如何能获得如此高的赞数呢?1)conditionsconditionals不同。2)Arrays.stream(boolean[])根本不存在。 - Nikolas Charalambidis
@NikolasCharalambidis 感谢您的反馈。第一个问题是类型错误,第二个问题是我没有意识到 Arrays.asStream(boolean[]) 缺失了。看起来很奇怪,但这就是现实吧。我将其更改为使用索引数组的 IntStream。在我看来不是最好的解决方案,但这是最便宜的选项。 - VLAZ

0

可以使用while运算符执行迭代。定义一个变量来控制正值的增量,另一个变量来评估数组的每个元素。这两个变量将成为我们的停止条件,该方法将返回解决方案,当存在单个正值时返回true,在所有其他情况下返回false。

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

或者按照建议,我们可以使用:

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;
}

2
在这种情况下,使用带有 iwhile 循环有点啰嗦 :) - Nowhere Man

0

使用 Stream API,您可以将其重写为以下形式(虽然看起来不像普通循环那么“实用”):

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]);
}

通过 @VLAZ 建议的更改,恢复初始版本:

import java.util.stream.*;

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

2
这是一种非常迂回的检查方式。使用 Arrays.stream(conditionals).filter(x -> x).limit(2).count() 仍将使用 Stream API,而且它是正确的、简短的和易读的。 - VLAZ
是的,限制(2)!:\ - Nowhere Man

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接