执行元组算术的优雅方法

在 Python 2.7中执行 tuple 算术的最优雅和简洁的方法是什么(不需要用运算符重载创建我自己的类) ?

假设我有两个元组:

a = (10, 10)
b = (4, 4)

我想要的结果是

c = a - b = (6, 6)

我目前使用:

c = (a[0] - b[0], a[1] - b[1])

我也试过:

c = tuple([(i - j) for i in a for j in b])

但结果是 (6, 6, 6, 6)。我相信上面的代码可以作为一个嵌套的 for 循环,在结果中产生4个迭代和4个值。

77886 次浏览

使用 zip和生成器表达式:

c = tuple(x-y for x, y in zip(a, b))

演示:

>>> a = (10, 10)
>>> b = (4, 4)
>>> c = tuple(x-y for x, y in zip(a, b))
>>> c
(6, 6)

使用 itertools.izip获得高效的内存解决方案。

zip的帮助:

>>> print zip.__doc__
zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]


Return a list of tuples, where each tuple contains the i-th element
from each of the argument sequences.  The returned list is truncated
in length to the length of the shortest argument sequence.

一个选择是,

>>> from operator import sub
>>> c = tuple(map(sub, a, b))
>>> c
(6, 6)

itertools.imap可以作为 map的替代品。

当然,你也可以使用从 operatoraddmuldiv等其他函数。

但是我会认真考虑转移到另一种数据结构,因为我不认为这种类型的问题适合 tuple

如果你在寻找快速,你可以使用 numpy:

>>> import numpy
>>> numpy.subtract((10, 10), (4, 4))
array([6, 6])

如果你想把它保持在元组中:

>>> tuple(numpy.subtract((10, 10), (4, 4)))
(6, 6)

这也可以在完全没有导入的情况下很好地完成,尽管 lambda 通常是不受欢迎的:

tuple(map(lambda x, y: x - y, a, b))

如果你想得到一个坐标平面上两点之间的距离,你应该使用两对减法的绝对值。

tuple(map(lambda x ,y: abs(x - y), a, b))

我的元素智能元组算术助手

支持的操作: + ,-,/,* ,d

Operation = ‘ d’计算二维坐标平面上两点之间的距离

def tuplengine(tuple1, tuple2, operation):
"""
quick and dirty, element-wise, tuple arithmetic helper,
created on Sun May 28 07:06:16 2017
...
tuple1, tuple2: [named]tuples, both same length
operation: '+', '-', '/', '*', 'd'
operation 'd' returns distance between two points on a 2D coordinate plane (absolute value of the subtraction of pairs)
"""
assert len(tuple1) == len(tuple2), "tuple sizes doesn't match, tuple1: {}, tuple2: {}".format(len(tuple1), len(tuple2))
assert isinstance(tuple1, tuple) or tuple in type(tuple1).__bases__, "tuple1: not a [named]tuple"
assert isinstance(tuple2, tuple) or tuple in type(tuple2).__bases__, "tuple2: not a [named]tuple"
assert operation in list("+-/*d"), "operation has to be one of ['+','-','/','*','d']"
return eval("tuple( a{}b for a, b in zip( tuple1, tuple2 ))".format(operation)) \
if not operation == "d" \
else eval("tuple( abs(a-b) for a, b in zip( tuple1, tuple2 ))")

JFYI,在我的笔记本电脑中的执行时间为100000次迭代

np.subtract(a, b):0.18578505516052246

返回文章页面 0.09348797798156738

tuple(map(lambda x, y: x - y, a, b)).0.07900381088256836

from operator import sub tuple(map(sub, a, b)).0.044342041015625

我觉得接线员看起来更优雅。

作为对川崎光平答案的补充,在速度方面,原来的解决方案实际上是最快的(至少有两个元组的长度)。

>>> timeit.timeit('tuple(map(add, a, b))',number=1000000,setup='from operator import add; a=(10,11); b=(1,2)')
0.6502681339999867
>>> timeit.timeit('(a[0] - b[0], a[1] - b[1])',number=1000000,setup='from operator import add; a=(10,11); b=(1,2)')
0.19015854899998885
>>>

因为在你的问题中只有2-数字元组的例子,对于这种类似坐标的元组,你可能很擅长使用简单的内置“复杂”类:

>>> a=complex(7,5)
>>> b=complex(1,2)
>>> a-b
>>> c=a-b
>>> c
(6+3j)
>>> c.real
6.0
>>> c.imag
3.0