测试3个中的4个是否为真的逻辑

165

如果且仅当4个布尔值中有3个为真时,我想返回True

我得到的最接近的结果是(x ^ y) ^ (a ^ b):

我该怎么办?


10
嗯,我能想到的唯一方法是使用计数,好问题! :) - I am Cavic
10
你的想法并不错,但你需要注意否定:当只有一个否定值为真时,not a ^ not b ^ not c ^ not d 才为真。这意味着,在原来的值中,恰好有一个是假的。 - Ingo
23
你在这些细节背后的实际问题是什么? - Wolf
5
当只有一个是假的并且其中三个是假的时,如果@Ingo不是a、不是b、不是c、也不是d,则返回true。 - NameSpace
10
明显的非计数解决方案是 (!a&&b&&c&&d) || (a&&!b&&c&&d) || (a&&b&&!c&&d) || (a&&b&&c&&!d) - Jason C
显示剩余9条评论
27个回答

248

我建议以表达你想要的方式编写代码。如果你希望有3个值为真,那么在某处出现值3似乎是很自然的。

例如,在C++中:

if ((int)a + (int)b + (int)c + (int)d == 3)
    ...

这在C++中有明确定义: 标准(§4.7/4)指出,将bool转换为int将得到期望的值0或1。

在Java和C#中,您可以使用以下结构:

if ((a?1:0) + (b?1:0) + (c?1:0) + (d?1:0) == 3)
    ...

23
这是一个很好的回答。看起来这似乎是一种X/Y问题。“他想用Y做X,但不知道怎么用Y。于是他问Y而不是问X。”除非他在设计逻辑电路之类的东西(那他就应该去错了地方),否则最好以一种易于阅读的方式解决此问题。 - NothingsImpossible
2
@NothingsImpossible 这个问题跟 XY 毫无关系,它是一个明确而简单的编程常见问题解决方案。Y 是无关紧要的。 - Ярослав Рахматуллин
谢谢!这确实是我本来想做的,但我的想法太笨拙了,以至于我只能使用布尔逻辑。 - Simon Kuang
3
“if (!!a + !!b + !!c + !!d == 3)” 更容易书写,但我不确定编译器是否会进行优化。 - phuclv
实际上,这甚至不关心OP的问题。 - bot47
2
请注意,在C++中,从布尔型转换为整型不是必需的。 - PlasmaHH

90

#1: 使用条件运算符 ?::3或4个操作

A ^ B ? C & D : ( C ^ D ) & A

#2 非分支,7个操作

(A ^ B ^ C ^ D) & ((A & B) | (C & D))

在我还对所有东西进行剖析的时候,我发现非分支解决方案在每个操作上比较快,因为CPU可以更好地预测代码路径,并同时执行更多的操作。然而,在这里的分支语句中要少大约50%的工作量。


18
虽然其他回答对于大多数编程语言更好,但是在纯布尔逻辑中,你的第二个回答是最佳的。 - Brilliand
2
请查看以下网址中的Wolframalpha真值表:https://www.wolframalpha.com/input/?i=%28A+xor+B+xor+C+xor+D%29+and+%28%28A+and+B%29+or+%28C+and+D%29%29+truth+table,用于问题#2。 - Sawny

69
如果这是Python,我会写成:
if [a, b, c, d].count(True) == 3:

或者

if [a, b, c, d].count(False) == 1:

或者

if [a, b, c, d].count(False) == True:
# In Python True == 1 and False == 0

或者

print [a, b, c, d].count(0) == 1

或者

print [a, b, c, d].count(1) == 3

或者

if a + b + c + d == 3:

或者

if sum([a, b, c, d]) == 3:

所有这些工作都是因为在Python中,布尔值是整数的子类。

if len(filter(bool, [a, b, c, d])) == 3:

或者,受到这个 巧妙的技巧 的启发,

data = iter([a, b, c, d])
if not all(data) and all(data):

17
+1这个问题可以通过正确将其翻译为Python来解决。 - Wolf
这有点危险,因为在Python的布尔上下文中,人们可能会返回任何非零整数。旧的C语言技巧在Python中也适用:a=5;not not a == 1。没有真正的布尔类型的缺点。 - Voo
@Voo 我们还有 bool :) - thefourtheye
@thefourtheye 啊是的,确实比双重否定技巧/黑客更好。 - Voo
JS版本:if ([x,y,z,w].filter(x => x).length == 3)(注意:它需要ES6中的箭头函数语法)。 - ComFreek
1
或者......或者......或者......应该有一种--最好只有一种--明显的方法来做到这一点。 :-/ :-) - rz.

53

长而非常简单的(离散)正规式:

 (~a & b & c & d) | (a & ~b & c & d) | (a & b & ~c & d) | (a & b & c & ~d)

可能可以简化,但那需要更多的思考:P


2
@Ben,这只是给你展示了它的各种正常形式,而这个已经是在(DNF)中了。 - Riking
8
这个 (a & b & (c ^ d)) | ((a ^ b) & c & d) 怎么样? - user253751
2
是的,@immibis,根据Wolfram Alpha的说法,它的DNF是我写的公式,因此它是相同的布尔函数。 - Gastón Bengolea
2
+1 是因为我认为阅读代码的人会比其他答案更快地理解所尝试的内容。 - Boluc Papuccuoglu

34

1
该死!他们应该给出多个赞同答案的选项!特别是使用 Wolfram Alpha 来证明你的答案是正确的,这是非常好的事情! - Durai Amuthan.H

23

如果您想在编程语言中使用此逻辑,我的建议是

bool test(bool a, bool b, bool c, bool d){
    int n1 = a ? 1 : 0;
    int n2 = b ? 1 : 0;
    int n3 = c ? 1 : 0;
    int n4 = d ? 1 : 0;

    return n1 + n2 + n3 + n4 == 3;
}

或者,如果您愿意,您可以将所有这些内容放在一行中:

return (a ? 1 : 0) + (b ? 1 : 0) + (C ? 1 : 0) + (d ? 1 : 0) == 3;

此外,您可以将此问题推广至 n of m
bool test(bool *values, int n, int m){
    int sum = 0;
    for(int i = 0; i < m; i += 1){
        sum += values[i] ? 1 : 0;
    }
    return sum == n;
}

12
抢先一步了。可读性胜过聪明才智,每一次都是如此。+1 - Mike G

20

这个答案取决于表示系统,但如果只有0被解释为false,且not(false)始终返回相同的数值,那么not(a) + not(b) + not(c) + not(d) = not(0)就能解决问题。


18

请注意,SO是用于编程问题而非纯逻辑问题,因此答案显然取决于选择的编程语言。一些语言支持其他语言不常见的功能。

例如,在C++中,您可以使用以下方式测试条件:

(a + b + c + d) == 3

如果语言支持从布尔类型自动转换为整数类型,这应该是执行检查的最快方式。但是,对于这个问题并没有通用答案。


2
这是我要发布的答案。不过需要补充一点,根据所使用的编程语言,你想要的答案可能是-3。在VB中,True等于-1。 - Tom Collins

12

对你来说,“最好”是什么意思? - Wolf
有趣的。我参考了楼主的解决方案,然后去除了一些不好的情况。 - Cruncher

11

检查至少有nBoolean为真(n必须小于或等于所有Boolean的总数:p)

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) >= n) {
    // do the rest
}

编辑:在@Cruncher的评论后

检查4个中的3个boolean

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) == 3) {
    // do the rest
}

另一个:

((c & d) & (a ^ b)) | ((a & b) & (c ^ d)) (详细信息)


OP想要恰好n,而不是至少n。但这很容易从这个解决方案进行更改。 - Cruncher
2
@Wolf 那个问题应该发到 StackUnderflow.com 上 :p - Not a bug

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