大多数pythonic的方式来'或'元组?

时间:2015-11-16 19:45:35

标签: python python-2.7 tuples iterable-unpacking

我有一个返回布尔值的三元素元组的方法,我在循环中调用它。我想最终得到一个包含单个元组的or结果的三元素元组。如果该方法只返回一个布尔值,那么它只是:

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

我可以用一些优雅的方式或method()现在返回的元组来概括它吗?我当然可以这样做:

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

但似乎有点不雅。

编辑:澄清我想在两种情况下都返回结果 - 首先是布尔值,然后是布尔值元组

2 个答案:

答案 0 :(得分:6)

您可以使用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()中。

您也可以在调用zip中将调用移至method(j),而不是将其分配给中间变量。我认为它使它的可读性稍差,但这是个人偏好的问题。

答案 1 :(得分:2)

让我们解开一点。

没有内置的方法可以在两个元组上执行元素明确的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会将元组列表的所有第一/第二/第三个值组合为n长度元组,其中n是结果数,any有效or他们在一起。 EG:

>>> 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,因此您可以考虑使用整数类似的模型。 for循环/多重赋值版本:

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

vs累积和总结结果列表:

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

如果您的for循环没有任何其他正文,则此版本特别好,因为您可以将整个内容折叠到您喜欢的任何级别的生成器表达式/列表推导中:

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