2015-11-16 31 views
0

我有一个方法返回一个三元组元组的布尔值,我把它称为一个循环。我想最终得到一个包含单个元组的or结果的三元组元组。如果方法只返回一个布尔值,这纯粹是:大多数pythonic的方式来'或'元组?

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

你有一个特别的原因是使用的'bool's位或操作符? –

+0

@Josh:这就是代码中使用的 - 我应该改变它还是? –

+2

我会这样想的。如果您想了解更多信息,请参阅[Python布尔运算符vs按位运算符](http://stackoverflow.com/q/3845018)。 –

回答

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是多少的结果,并且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))) 
+0

嗯 - 将思考这一点:)仍然如何适应循环?我的意思是说它不需要更多的线条? –

+0

该版本不需要明确的for循环 - 生成器表达式('用于分组在zip(some_list)')中负责迭代。 –

+0

查看我的问题中的循环 - 这是一个大循环 –

6

的元组您可以用拉链列表理解这一点。

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

如果它必须是一个元组,你可以更改列表比较到发电机和tuple()包裹。

您也可以将呼叫转移到method(j),而不是将其分配给中间变量。我认为这使得它不易读,但这是个人喜好的问题。

+0

我仍然发现它有点矫枉过正 - 它只有三个值... –

+0

@Mr_and_Mrs_D它比手动更有效,再加上无论你有多少值,这都会工作。我不明白你认为什么解决方案会更“优雅”。 –

+1

你的意思是'result = res1 |结果[0],res2 |结果[1],res3 | result [2]'效率低于'result = [a | b for a,b in zip(result,xor)]''?你可以计时吗? –

相关问题