'or' 元组的大多数 pythonic 方式?

Most pythonic way to 'or' tuples?

我有一个方法 return 是一个布尔值的三元素元组,我在循环中调用它。我想最终得到一个包含各个元组的 or 结果的三元素元组。如果该方法仅 returned 一个布尔值,则它只是:

result = False
for j in some_list: # there is more processing in the loop, omitted
    result |= method(j)
return result

我能否以某种优雅的方式将其概括为 method() 现在 return 的元组?我当然可以:

result = False, False, False
for j in some_list:
    res1, res2, res3 = method(j)
    result = res1 | result[0], res2 | result[1], res3 | result[2]
return result

不过好像有点不雅

编辑:澄清我想return两种情况下的结果——首先是布尔值,然后是布尔值元组

您可以使用 zip 在列表理解中执行此操作。

result = False, True, False
xor = True, True, False
result = [a|b for a,b in zip(result,xor)]
print(result)

或者在您的例子中:

result = False, False, False
for j in some_list:
    xor = method(j)
    result = [a|b for a,b in zip(result,xor)]

如果它必须是元组,您可以将列表 comp 更改为生成器并将其包装在 tuple().

您还可以将对 method(j) 的调用移到对 zip 的调用中,而不是将其分配给中间变量。我认为这会降低可读性,但这是个人喜好问题。

让我们稍微解压一下。

没有内置的方法可以对两个元组执行按元素 or(逻辑或按位)。 Morgan Thrapp 的回答显示了一种编写您自己的答案的好方法,因此如果您想在 for 循环中保持 运行 状态,这就是我要走的路。熟悉 Python 的人将很容易理解生成器表达式 - 尽管如果我实际上不想要按位版本,我会使用 tuple(a or b for a, b in zip(result, new_result)) 而不是 a | b

Numpy 数组有一个按元素工作的 logical_or 函数,但如果你只有中等数量的布尔元组,那将是严重的矫枉过正。

保持 运行 状态的另一种方法是收集所有结果元组并从结果元组列表中计算最终的布尔值元组。如果您要提前终止循环(例如,如果您的累积结果元组的所有元素都为 True)或者如果您的循环有足够的迭代次数以至于内存使用很重要,那么这将是不合适的。不过,根据您的口味,它可能会更清晰。这与保留 运行 总数值与仅在循环运行时收集值并在之后求和的决定本质上是相同的决定,并且如果例如您将 for 循环重做为结果的迭代器,这将是我的首选方法元组。

看起来像这样:

result_list = []
for j in some_list:
    result_list.append(method(j))
result = tuple(any(grouped) for grouped in zip(*result_list))

zip 在星号扩展的结果列表中会将元组列表的所有 first/second/third 值分组为 n 长度元组,其中 n 是结果数,any 有效地 or 将它们组合在一起。例如:

>>> result_list = [(False, True, False), (True, False, False), (False, False, False), (True, True, False)]
>>> zip(*result_list)
[(False, True, False, True), (True, False, False, True), (False, False, False, False)]
>>> tuple(any(grouped) for grouped in zip(*result_list))
(True, True, False)

由于布尔值上的 or 等价于数字上的加法,而 any 等价于 sum,您可以考虑使用整数的类似模型。 loop/multiple 赋值版本:

sums = (0, 0, 0)
for j in some_list:
    result = method(j)
    sums[0] += result[0]
    sums[1] += result[1]
    sums[2] += result[2] 

vs 生成器表达式 运行 和版本:

sums = (0, 0, 0)
for j in some_list:
    result = method(j)
    sums = (a + b for a, b in zip(sums, result))

与累积和总结结果列表:

result_list = []
for j in some_list:
    result_list.append(method(j))
sums = tuple(sum(grouped) for grouped in zip(*result_list))

如果你的 for 循环没有任何其他主体,这个版本特别好,因为你可以将整个事情折叠成你喜欢的任何级别的生成器 expressions/list 理解:

result_list = [method(j) for j in some_list]
sums = tuple(sum(grouped) for grouped in zip(*result_list))

或:

sums = tuple(sum(grouped) for grouped in zip(*(method(j) for j in some_list)))