如何判断* exact * one boolean是否为真,没有类型转换?

时间:2013-02-15 04:21:38

标签: boolean logic

给定一个任意的布尔列表,确定完全其中一个是真的最优雅的方法是什么?

最明显的黑客攻击是类型转换:将其转换为0的{​​{1}}和false的{​​{1}},然后将它们相加,然后返回1

我想知道是否有办法没有将它们转换为整数,实际上使用布尔逻辑

(这似乎应该是微不足道的,idk,长周)

编辑:如果不明显,这更像是一个代码高尔夫/理论问题。我不喜欢在PROD代码中使用类型转换/ int添加,我只是感兴趣,如果有没有这样做的方式。

编辑2:对不起,这是一个漫长的一周,我并没有很好地解释自己。让我试试这个:

在布尔逻辑中,如果所有布尔值都为真,则对一组布尔值进行AND运算是正确的,如果其中至少有一个为真,则该集合为真。如果只有一个布尔值为真,那么是否存在一个逻辑结构?例如,对于两个布尔值的集合,XOR就是这个,但不止于此,它就会失败。

19 个答案:

答案 0 :(得分:8)

你实际上只能使用布尔逻辑来实现这一点,尽管在你的例子中可能没有实际价值。布尔版本比简单计算真值的数量要多得多。

无论如何,为了满足求知欲,这里也是如此。首先,使用一系列XOR的想法很好,但它只能让我们走到一半。对于任何两个变量 x y

x y

只要其中一个是真的,

就是真的。但是,如果添加第三个变量 z

,则不会继续如此

x y z

第一部分 x y ,如果 x y 中只有一个是真正。如果 x y 为真,则 z 必须为false才能使整个表达式为true,这就是我们想要的。但请考虑如果 x y 都为真,会发生什么。然后 x y 为false,但如果 z 也为真,整个表达式也会变为true。因此,无论是一个变量还是全部三个都必须为真。一般来说,如果你有一个XOR链的陈述,那么如果一个不均匀的数字变量为真,那就是真的。

由于一个数字不均匀,这可能证明是有用的。当然,检查不确定数量的真相是不够的。我们还需要确保只有一个变量是真的。这可以通过采用所有两个变量对并检查它们都不是真的以成对方式完成。将这两个条件组合在一起确保如果变量为真,则只有一个条件。

下面是一个用于说明该方法的小型Python脚本。

from itertools import product

print("x|y|z|only_one_is_true")
print("======================")
for x, y, z in product([True, False], repeat=3):
    uneven_number_is_true = x ^ y ^ z
    max_one_is_true = (not (x and y)) and (not (x and z)) and (not (y and z))
    only_one_is_true = uneven_number_is_true and max_one_is_true
    print(int(x), int(y), int(z), only_one_is_true)

这是输出。

x|y|z|only_one_is_true
======================
1 1 1 False
1 1 0 False
1 0 1 False
1 0 0 True
0 1 1 False
0 1 0 True
0 0 1 True
0 0 0 False

答案 1 :(得分:6)

使用普通布尔逻辑,可能无法实现您想要的效果。因为您要求的是真实评估,不仅基于真值,还基于其他信息(在这种情况下计算)。但是布尔评估是二进制逻辑,它不能依赖于操作数本身的其他任何东西。并且没有办法进行逆向工程以找到给定真值的操作数,因为可以有四种可能的操作数组合但只有两种结果。假设是假的,你可以判断它是否是因为你的情况下的F ^ F或T ^ T,以便可以根据这个确定下一个评估?。

答案 2 :(得分:3)

在澄清之后,这里没有整数。

 bool IsExactlyOneBooleanTrue( bool *boolAry, int size )
    {
      bool areAnyTrue = false;
      bool areTwoTrue = false;
      for(int i = 0; (!areTwoTrue) && (i < size); i++) {
        areTwoTrue = (areAnyTrue && boolAry[i]);
        areAnyTrue |= boolAry[i];
      }
      return ((areAnyTrue) && (!areTwoTrue));
    }

答案 3 :(得分:2)

使用递归可以很好地完成,例如在Haskell

-- there isn't exactly one true element in the empty list
oneTrue [] = False 
-- if the list starts with False, discard it
oneTrue (False : xs) = oneTrue xs
-- if the list starts with True, all other elements must be False
oneTrue (True : xs) = not (or xs)

答案 4 :(得分:1)

当然,你可以做这样的事情(伪代码,因为你没有提到语言):

found = false;
alreadyFound = false;
for (boolean in booleans):
    if (boolean):
        found = true;
        if (alreadyFound):
            found = false;
            break;
        else:
            alreadyFound = true;
return found;

答案 5 :(得分:1)

没有人提到我们正在寻找的这种“操作”与大多数语言中的布尔AND和OR类似。这是Java中的一个实现:

public static boolean exactlyOneOf(boolean... inputs) {
    boolean foundAtLeastOne = false;
    for (boolean bool : inputs) {
        if (bool) {
            if (foundAtLeastOne) {
                // found a second one that's also true, shortcut like && and ||
                return false;
            }
            foundAtLeastOne = true;
        }
    }
    // we're happy if we found one, but if none found that's less than one
    return foundAtLeastOne;
}

答案 6 :(得分:1)

由于目前已有大量阅读,因此请快速清理并获得其他信息。

选项1:

询问是否只有第一个变量为true,或者只有第二个变量,...或只有第n个变量。

x1 & !x2 & ... & !xn |
!x1 & x2 & ... & !xn |
...
!x1 & !x2 & ... & xn

此方法的缩放比例为 O(n ^ 2),在找到第一个正匹配项后,评估停止。因此,如果可能存在正匹配,则首选。

选项2:

询问是否总共至少有个变量。此外,还要检查每对中最多包含一个真正变量的变量(Anders Johannsen的答案)

(x1 | x2 | ... | xn) &
(!x1 | !x2) &
...
(!x1 | !xn) &
(!x2 | !x3) &
...
(!x2 | !xn) &
...

由于可能的配对数,该选项还会缩放为 O(n ^ 2)。延迟评估会在第一个反例之后停止公式。因此,如果它可能存在负匹配,则是首选。

(选项3):

此选项涉及减法,因此对于受限设置,是有效答案。但是,它争论了如何在不受限制的笔划中循环使用值不是最有益的解决方案。

将x1 ... xn作为二进制数x处理。减去一个,然后与结果相加。输出为零<=> x1 ... xn最多包含一个真实值。 (旧的“ 2的幂次方”算法)

x    00010000
x-1  00001111
AND  00000000

如果位已经存储在这样的位板上,则这可能比循环更有利。不过,请记住,这会破坏可读性,并受到可用板长的限制。

最后一个引起注意的注意事项:到现在为止,存在一种称为计算机科学的堆栈交换,正是针对这种算法问题的

答案 7 :(得分:0)

那个python脚本很好地完成了这项工作。这是它使用的单线:

((x∨(y∨z))∧(¬(x∧y)∧(¬(z∧x)∧¬(y∧z))))

答案 8 :(得分:0)

Retracted for PrivacyAnders Johannsen 已经提供了正确且简单的答案。但是这两种解决方案都不能很好地扩展(O(n^2))。如果性能很重要,您可以坚持使用以下解决方案,该解决方案在 O(n) 中执行:

def exact_one_of(array_of_bool):
    exact_one = more_than_one = False
    for array_elem in array_of_bool:
        more_than_one = (exact_one and array_elem) or more_than_one
        exact_one = (exact_one ^ array_elem) and (not more_than_one)
    return exact_one

(为了简单起见,我使用了 python 和 for 循环。当然,这个循环可以展开为一系列 NOT、AND、OR 和 XOR 操作)

它通过跟踪每个布尔变量/列表条目的两个状态来工作:

  1. 从列表的开头到此条目是否只有一个“True”?
  2. 从列表的开头到此条目是否有多个“True”?

列表条目的状态可以简单地从先前的状态和相应的列表条目/布尔变量导出。

答案 9 :(得分:0)

蟒蛇: 让我们看看使用示例... 步骤:

  1. 下面的函数 exactly_one_topping 需要三个参数

  2. 将它们的值存储在列表中作为 True, False

  3. for 循环检查,如果只有一个真值

def exactly_one_topping(ketchup, mustard, onion):
    
  args = [ketchup,mustard,onion]
  for i in args:
      if args.count(True) == 1:   # check if Exactly one value is True
          return True
      else:
          return False

答案 10 :(得分:0)

// Javascript 在数组上使用.filter()并检查新数组的长度。

// Example using array
isExactly1BooleanTrue(boolean:boolean[]) {
  return booleans.filter(value => value === true).length === 1;
}

// Example using ...booleans
isExactly1BooleanTrue(...booleans) {
  return booleans.filter(value => value === true).length === 1;
}

答案 11 :(得分:0)

Python:

boolean_list.count(True) == 1

答案 12 :(得分:0)

没有循环就不可能。在java实现中检查BitSet基数()。 http://fuseyism.com/classpath/doc/java/util/BitSet-source.html

答案 13 :(得分:0)

执行此操作的一种方法是执行成对AND,然后检查任何成对比较是否与链式OR一起返回true。在python中,我将使用

实现它
from itertools import combinations

def one_true(bools):
    pairwise_comp = [comb[0] and comb[1] for comb in combinations(bools, 2)]
    return not any(pairwise_comp)

这种方法很容易推广到任意长度的列表,尽管对于很长的列表,可能的对数量增长很快。

答案 14 :(得分:0)

好的,再试一次。调用不同的布尔值b[i],并调用它们的一部分(数组的范围)b[i .. j]。定义函数none(b[i .. j])just_one(b[i .. j])(如果需要,可以替换递归定义以获取显式公式)。我们使用C表示法进行逻辑运算(&&是和,||是或^对于xor(不是真的在C中),!不是):< / p>

none(b[i .. i + 1]) ~~> !b[i] && !b[i + 1]
just_one(b[i .. i + 1]) ~~> b[i] ^ b[i + 1]

然后递归:

none(b[i .. j + 1]) ~~> none(b[i .. j]) && !b[j + 1]
just_one(b[i .. j + 1] ~~> (just_one(b[i .. j]) && !b[j + 1]) ^ (none(b[i .. j]) && b[j + 1])

您对just_one(b[1 .. n])感兴趣。

这些表达将变得可怕。

玩得开心!

答案 15 :(得分:0)

如果没有,计算如何计算有多少是真的?当然,你可以做一些凌乱的事情(C语法,我的Python很可怕):

for(i = 0; i < last && !booleans[i]; i++)
     ;
if(i == last)
     return 0;  /* No true one found */
/* We have a true one, check there isn't another */
for(i++; i < last && !booleans[i]; i++)
     ;
if(i == last)
     return 1; /* No more true ones */
else
     return 0; /* Found another true */ 

我相信你会同意胜利(如果有的话)是轻微的,而且可读性很差。

答案 16 :(得分:0)

booleanList.Where(y =&gt; y).Count()== 1;

答案 17 :(得分:-2)

为什么不这样做:

count = 0
for (b in booleans):
  if (b):
     count = count + 1
return count == 1

简短,甜蜜,任何人都不可能误解这里发生的事情。如果 对应用程序至关重要的性能,那么在重新组织计算和数据表示方面还有很多工作要做。

答案 18 :(得分:-3)

我们可以这样做: -

if (A=true or B=true)and(not(A=true and B=true)) then
<enter statements>
end if