测试4之3为真的逻辑


163

我只想在True4个布尔值中有3个为真时返回。

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

我该怎么办?


10
嗯,我想不出数学公式的唯一方法就是使用计数。好问题!:)
我是Cavic 2014年

10
您的想法还不错,但是您必须接受否定:not a ^ not b ^ not c ^ not d当恰好一个否定值之一为true时为true。这意味着从原始值来看,恰好一个是假的。
Ingo 2014年

23
您在此详细信息背后的实际问题是什么?
狼2014年

5
@Ingo not a ^ not b ^ not c ^ not d在只有一个为false和三个为false的情况下返回true。
NameSpace 2014年

9
显而易见的非计数解决方案是(!a&&b&&c&&d) || (a&&!b&&c&&d) || (a&&b&&!c&&d) || (a&&b&&c&&!d)
詹森·C

Answers:


248

我建议以表明您的意思的方式编写代码。如果您希望3个值是真实的,那么对我来说,自然的是3个值出现在某个地方。

例如,在C++

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

这在C++以下各项中有很好的定义:standard (§4.7/4)表示转换boolint会给出期望值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。” 除非他正在设计逻辑电路或类似的东西(然后他会在错误的位置),否则执行此操作的最佳方法是可读性强
没什么可能,2014年

2
@NothingsImpossible这个问题没有XY。这是解决编程中一个常见问题的明确而直接的问题。Y无关紧要。
ЯрославРахматуллин

谢谢!这确实是我的本意,但是我的想法太笨拙,以至于我不了解布尔逻辑。
Simon Kuang

3
if (!!a + !!b + !!c + !!d == 3)更容易编写,尽管我不知道编译器是否对此进行了优化
phuclv 2014年

2
请注意,在c ++中,没有必要将布尔值转换为整数。
PlasmaHH 2014年

90

#1:使用分支?:3或4个操作

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

#2非分支,7个操作

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

回到过去,当我分析所有内容时,我发现非分支解决方案的操作速度要快得多,因为CPU可以更好地预测代码路径,并串联执行更多操作。不过,这里的分支语句中的工作量减少了约50%。


18
+1-尽管其他答案对大多数编程语言都更好,但在纯布尔逻辑中,您的#2是最佳答案。
Brilliand


68

如果这是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来解决该问题。

这有点危险,因为人们可能会在python的布尔值上下文中返回任何非零整数。旧的C技巧也可以在python中使用:a=5;not not a == 1。没有真正的布尔类型的缺点。
Voo

@Voo我们也有bool:)
thefourtheye 2014年

@thefourtheye是的,比双重否定技巧/ hack好得多。
Voo

1
或...或....或....应该有一种-最好只有一种-显而易见的方法。:-/ :-)
rz。

53

长但很简单的(析取)范式:

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

它可以简化,但是需要更多的思考:P


2
@Ben只是为您提供各种正常形式,这已经在(DNF)中。
2014年

8
怎么(a & b & (c ^ d)) | ((a ^ b) & c & d)
user253751 2014年

2
是的,@ immibis,根据Wolfram Alpha的说法,其DNF是我编写的公式,因此它是相同的布尔函数。
加斯顿Bengolea

2
+1是因为我认为阅读代码的人比其他答案会更快地理解尝试的内容。
Boluc Papuccuoglu 2014年


22

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

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
MikeTheLiar 2014年

20

此答案取决于表示形式的系统,但是如果0是唯一解释为false的值,并且not(false)始终返回相同的数字值,则not(a) + not(b) + not(c) + not(d) = not(0)可以解决问题。


18

请记住,如果是针对编程问题,而不仅仅是逻辑问题,那么答案显然取决于编程语言的选择。某些语言支持其他语言不常见的功能。

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

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

这应该是支持从布尔类型到整数类型的自动(低级)转换的语言中进行检查的最快方法。但是同样,对于这个问题没有普遍的答案。


2
这就是我要发布的答案。不过要增加一件事,根据所使用的编程语言,您想要的答案将是-3。在VB中,True = -1。
汤姆·柯林斯


11
((a xor b) xor (c xor d)) and ((a or b) and (c or d))

拳头表达式从4中搜索1或3。true第二个表达式从4中消除0或1(有时2)true


11

Java 8过滤掉假值,并计算剩余的真值:

public static long count(Boolean... values) {
    return Arrays.stream(values).filter(t -> t).count();
}

然后您可以按以下方式使用它:

if (3 == count(a, b, c, d)) {
    System.out.println("There... are... THREE... lights!");
}

容易推广到检查nm项目是真实的。


11

要至少检查n所有Boolean的真实性,(n必须小于或等于Boolean:p的总数)

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

编辑:@Cruncher的评论后

要检查4 boolean之3

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。但是,这是从该解决方案一个简单的变化
排排坐

2
@狼这个问题属于StackUnderflow.com:p
不是bug

10

您可以使用LINQ在C#中解决此问题的方法:

bool threeTrue = new[] { a, b, x, y }.Count(x => x) == 3;

10

那就是对称布尔函数S₃(4)。对称布尔函数是布尔函数,它仅取决于输入集的数量,而不取决于它们是哪些输入。Knuth在《计算机编程艺术》第4卷的7.1.2节中提到了这种类型的功能。

S₃(4) 可以通过以下7个操作来计算:

(x && y && (a || b)) ^ ((x || y) && a && b)

克努特显示,这是最佳的,这意味着你不能用正常的运营商在不到7个操作做到这一点:&&, || , ^, <,>

但是,如果您要使用1用于true和0false 的语言,也可以轻松使用加法:

x + y + a + b == 3

这使你的意图很明确。


9
(a && b && (c xor d)) || (c && d && (a xor b))

从纯粹的逻辑观点来看,这就是我的想法。

根据信鸽原理,如果正好为3,则a和b为真,或者c和d为真。然后,只需将每种情况与其他两种情况中的一种恰好相加即可。

Wolfram真值表


这等效于NameSpace的第二个解决方案。
Brilliand 2014年

@Brilliand似乎与我不同。他的异或运算结果全部为3或1,然后通过要求2个不同的组中至少有一个排除1。(汇总为1或3,至少2个)。我的需要两个不同组中的一个,然后恰好需要另一个组中的一个。
Cruncher 2014年

如果您的意思是等同的,mine <=> his那么我不知道该说些什么,因为这是可以预期的。
Cruncher 2014年

我想我的意思是,这个答案是好的,其方式与NameSpace的第二个解决方案的好方式完全相同,而没有添加NameSpace的(较早的)答案未涵盖的任何新内容。好吧,我还是会投票。
Brilliand

8

如果使用像Karnaugh Maps这样的逻辑可视化工具,则会发现这是一个问题,如果您想在if(...)行中编写逻辑术语,则无法避免使用完整的逻辑术语。Lopina已经展示了它,不可能将其编写得更简单。您可以考虑一下,但是对于您和机器而言,阅读起来仍然很困难。

计算解决方案还不错,它们显示了您的真正追求。如何有效地进行计数取决于您的编程语言。使用Python oder LinQ的数组解决方案很不错,但是请注意,这很慢。Wolf的(a + b + x + y)== 3可以很好且快速地工作,但前提是您的语言将“ true”等同于1。如果“ true”由-1表示,则必须测试-3: )

如果您的语言使用的是布尔值,则可以尝试对其进行显式编程(我将!=用作XOR测试):

if (a)
{
    if (b)
        return (x != y);    // a,b=true, so either x or y must be true
    else
        return (x && y);     // a=true, b=false, so x AND y must be true
}
else
{
    if (b)
        return (x && y);    // a=false, b=true, so x and y must be true
    else
        return false;       // a,b false, can't get 3 of 4
}

仅当x,y为布尔类型时,“ x!= y”才有效。如果它们是其他一些类型,其中0为false,其他均为true,则可能会失败。然后使用布尔XOR,或((bool)x!=(bool)y),或编写“ if(x)return(y == false)else return(y == true);”,这要多一些为计算机工作。

如果您的编程语言提供了三元?:运算符,则可以将其缩短为

if (a)
    return b ? (x != y) : (x && y);
else
    return b ? (x && y) : false;

这会保持一定的可读性,或者将其积极地削减为

return a ? (b ? (x != y) : (x && y)) : (b ? (x && y) : false);

这段代码恰好执行了三个逻辑测试(a状态,b状态,x和y比较),并且应该比这里的大多数其他答案要快。但是您需要对其进行评论,否则三个月后您将无法理解它:)


8

这里有很多好的答案。这是另一种没有其他人发表的表述:

 a ? (b ? (c ^ d) : (c && d)) : (b && c && d)

感谢您的回答,但是您可以添加一些有关其工作原理的评论吗?谢谢。
Deanna 2014年

(很抱歉,我接受了审核审核。):
Deanna

7

与第一个答案类似,但纯Java:

int t(boolean b) {
    return (b) ? 1 : 0;
}

if (t(x) + t(y) + t(a) + t(b) == 3) return true;
return false;

我更喜欢将它们计为整数,因为它使代码更易读。


7

Python中,要查看有多少个可迭代元素为True,请使用sum(这非常简单):

建立

import itertools

arrays = list(itertools.product(*[[True, False]]*4))

实际测试

for array in arrays:
    print(array, sum(array)==3)

输出量

(True, True, True, True) False
(True, True, True, False) True
(True, True, False, True) True
(True, True, False, False) False
(True, False, True, True) True
(True, False, True, False) False
(True, False, False, True) False
(True, False, False, False) False
(False, True, True, True) True
(False, True, True, False) False
(False, True, False, True) False
(False, True, False, False) False
(False, False, True, True) False
(False, False, True, False) False
(False, False, False, True) False
(False, False, False, False) False

5

如果您正在使用纸上(非编程)解决方案,那么您将追求K-maps和Quine-McCluskey算法,它们可帮助您最小化布尔函数。

就您而言,结果是

y = (x̄3 ^ x2 ^ x1 ^ x0) ∨ (x3 ^ x̄2 ^ x1 ^ x0) ∨ (x3 ^ x2 ^ x̄1 ^ x0) ∨ (x3 ^ x2 ^ x1 ^ x̄0)

如果要以编程方式执行此操作,可以使用非固定数量的变量和自定义的“阈值”,那么只需遍历一个布尔值列表并计算“ true”的出现就非常简单明了。


1
酒吧的开销是什么意思?我注意到它在列表中向下移动。
NameSpace 2014年

3
@NameSpace这是IMO太多人们用来表示“ not”的符号之一。


4
((a^b)^(x^y))&((a|b)&(x|y))

是你想要的。基本上,我接受了您的代码,并添加了检查是否实际上为3而不是3为假。


4

没有涉及递归的答案的编程问题? 不可思议!

有足够的“完全正确4个3中的”答案,但是这里有一个通用的(Java)版本,用于“完全正确n个n中的m”(否则递归实际上不值得)只是因为您可以:

public static boolean containsTrues(boolean[] someBooleans,
    int anIndex, int truesExpected, int truesFoundSoFar) {
  if (anIndex >= someBooleans.length) {
    return truesExpected == truesFoundSoFar; // reached end
  }
  int falsesExpected = someBooleans.length - truesExpected;
  boolean currentBoolean = someBooleans[anIndex];
  int truesFound = truesFoundSoFar + (currentBoolean ? 1 : 0);
  if (truesFound > truesExpected) {
    return false;
  }
  if (anIndex - truesFound > falsesExpected) {
    return false; // too many falses
  }
  return containsTrues(someBooleans, anIndex + 1, truesExpected,
      truesFound);
}

可以这样称呼:

 boolean[] booleans = { true, false, true, true, false, true, true, false };
 containsTrues(booleans, 0, 5, 0);

应该返回true(因为8个值中有5个是正确的,如预期的那样)。对“ true”和“ falses”一词不太满意,但是现在无法想到更好的名称……。请注意,当找到太多true 太多的false值时,递归就会停止。


@FélixSaparelli:不确定“真相”在这里是否适用……听起来您只对其中一个感到满意true。也许像containsNumberOfTrueValues()。顺便说一句:Smalltalk的命名会更适合这个,虽然:doesArray: someBooleans startingAt: anIndex containNumberOfTrueValues: anExpectedNumber foundSofar: aNumberFoundSoFar。对于某些Java开发人员来说,可能太长了,但是Smalltalkers从来都不害怕正确命名;-)
Amos M. Carpenter

那主要是幽默。并containsTruth表示“包含真理的一些未公开的金额”,从字面上看,所以我认为这是相当不错。
费利克斯Saparelli

3

由于可读性是一个大问题,因此您可以使用描述性函数调用(包装任何建议的实现)。如果此计算需要在多个地方进行,则函数调用是实现重用的最佳方法,并且可以清楚地说明您在做什么。

bool exactly_three_true_from(bool cond1, bool cond2, bool cond3, bool cond4)
{
    //...
}

3

在PHP中,使其更具动态性(以防万一您更改条件数等):

$min = 6;
$total = 10;

// create our boolean array values
$arr = array_map(function($a){return mt_rand(0,1)>0;},range(1,$total));

// the 'check'
$arrbools = array_map(function($a){return (int)$a;},$arr);
$conditionMet = array_sum($arrbools)>=$min;

echo $conditionMet ? "Passed" : "Failed";

2
(((a AND b) OR (x AND y)) AND ((a XOR b) OR (x XOR y)))

虽然我可以证明这是一个很好的解决方案,但Sam Hocevar的答案很容易写,以后也很容易理解。在我的书中,它变得更好。


1

这是我刚刚写的一些C#代码,因为您启发了我:

它接受任意数量的参数,并会告诉您其中n个是否正确。

    static bool boolTester(int n, params bool[] values)
    {
        int sum = 0;           

        for (int i = 0; i < values.Length; i++)
        {
            if (values[i] == true)
            {
                sum += 1;
            }                
        }
        if( sum == n)
        {
            return true;
        }            
        return false;                
    }

并且您这样称呼它:

        bool a = true;
        bool b = true;
        bool c = true;
        bool d = false;            

        bool test = false;
        test = boolTester(3, a, b, c, d);

因此,您现在可以随意测试7/9或15/100。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.