33

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

最明显的技巧是类型转换:将它们转换为0forfalse1for true,然后将它们相加,然后返回sum == 1.

我想知道是否有一种方法可以在将它们转换为整数的情况下执行此操作,实际上是使用 boolean logic

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

编辑:如果不是很明显,这更像是一个代码高尔夫/理论问题。我对在 PROD 代码中使用类型转换/int 加法并不大惊小怪,我只是感兴趣是否有办法做到这一点。

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

在布尔逻辑中,如果所有布尔值都为真,则对一组布尔值进行与运算为真,如果其中至少一个为真,则对集合进行或运算为真。如果恰好一个布尔值为真,是否有一个逻辑结构为真?例如,XOR 是用于两个布尔值的集合,但除此之外,它就会失败。

4

18 回答 18

13

您实际上可以仅使用布尔逻辑来完成此操作,尽管在您的示例中可能没有实际价值。布尔版本比简单地计算真值的数量要复杂得多。

无论如何,为了满足求知欲,就这样吧。首先,使用一系列 XOR 的想法很好,但它只让我们成功了一半。对于任意两个变量xy

xy

只要其中一个为真,则为真。但是,如果您添加第三个变量z ,这将不再适用,

xyz

如果xy中的一个为真,则第一部分xy仍然为真。如果xy为真,则z需要为假才能使整个表达式为真,这就是我们想要的。但是考虑一下如果xy都为真会发生什么。那么xy为假,但如果z也为真,则整个表达式也可以为真。因此,一个变量或三个变量都必须为真。通常,如果您有一个 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 错误
1 1 0 错误
1 0 1 错误
1 0 0 真
0 1 1 错误
0 1 0 真
0 0 1 真
0 0 0 错误
于 2015-10-21T20:19:11.413 回答
5

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

 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));
    }
于 2013-02-15T04:49:14.720 回答
4

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

found = false;
alreadyFound = false;
for (boolean in booleans):
    if (boolean):
        found = true;
        if (alreadyFound):
            found = false;
            break;
        else:
            alreadyFound = true;
return found;
于 2013-02-15T04:35:48.637 回答
4

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

于 2013-02-15T13:31:44.537 回答
4

没有人提到我们正在寻找的这个“操作”是类似于大多数语言中的布尔 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;
}
于 2016-09-05T17:01:31.043 回答
2

booleanList.Where(y => y).Count() == 1;

于 2013-02-15T04:49:42.687 回答
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)
于 2013-02-15T06:56:18.927 回答
2

由于现在有大量读取,这里有一个快速清理和附加信息。

选项1:

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

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

这种方法在O(n^2)中扩展,在找到第一个正匹配后停止评估。因此,如果可能存在正匹配,则首选。

选项 2:

询问总共是否至少有一个变量为真。另外检查每一对最多包含一个真实变量(安德斯约翰森的答案)

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

由于可能对的数量,此选项也可以按O(n^2)进行缩放。延迟评估在第一个反例之后停止公式。因此,如果可能存在负匹配,则它是优选的。

(选项 3):

此选项涉及减法,因此对于受限设置不是有效答案。然而,它认为循环值可能不是不受限制的设置中最有益的解决方案。

将 x1 ... xn 视为二进制数 x。减一,然后与结果。输出为零 <=> x1 ... xn 最多包含一个真值。(旧的“检查二的幂”算法)

x    00010000
x-1  00001111
AND  00000000

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

提高认识的最后一点:到目前为止,存在一个称为计算机科学的堆栈交换,它正是针对此类算法问题而设计的

于 2018-12-14T19:32:22.470 回答
1

一种方法是成对执行AND,然后检查是否有任何成对比较返回 true 与 chained OR。在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)

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

于 2017-04-04T10:40:19.787 回答
1

Python:

boolean_list.count(True) == 1
于 2020-06-05T00:10:30.797 回答
0

好的,再试一次。调用不同的布尔值b[i],并调用它们的一部分(数组的范围)b[i .. j]。定义函数none(b[i .. j])just_one(b[i .. j])(如果需要,可以替换递归定义以获得显式公式)。我们有,使用 C 符号进行逻辑运算(&&is and, ||is or, ^for xor (not really in C), !is not):

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]).

表情会变得很可怕。

玩得开心!

于 2013-02-16T03:56:27.467 回答
0

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

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

于 2016-04-18T10:46:43.020 回答
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;
}
于 2020-09-16T11:33:03.633 回答
0

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

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

  2. 将它们的值存储在列表中TrueFalse

  3. 通过检查计数是否精确为 1 来检查是否仅存在一个真值。

def exactly_one_topping(ketchup, mustard, onion):
    
  args = [ketchup,mustard,onion]
  if args.count(True) == 1:   # check if Exactly one value is True
      return True
  else:
      return False
于 2021-04-14T08:56:05.517 回答
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”?

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

于 2021-08-04T18:28:03.153 回答
-1

如果不计算,你要如何计算有多少是真的?当然,你可以做一些乱七八糟的事情(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 */ 

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

于 2013-02-15T05:04:46.840 回答
-1

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

于 2017-06-16T20:21:19.833 回答
-4

我们可以这样做:-

if (A=true or B=true)and(not(A=true and B=true)) then
<enter statements>
end if
于 2016-12-14T09:21:39.457 回答