【问题标题】:Elegant way to perform tuple arithmetic执行元组算术的优雅方式
【发布时间】:2013-06-29 09:05:59
【问题描述】:

在 Python 2.7 中执行元组运算的最优雅和简洁的方式是什么(无需创建我自己的运算符重载类)?

假设我有两个元组:

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 个值。

【问题讨论】:

  • 如果你做了很多这些并且它们并不特别需要是 tuples 你可以看看 numpy

标签: python python-2.7 numpy tuples


【解决方案1】:

作为对 Kohei Kawasaki 答案的补充,对于速度,原始解决方案实际上是最快的(至少对于长度为两个元组)。

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

【讨论】:

  • 如果你的元组有百万个元素怎么办?是不是要把操作一一列出来?
  • @RaminMelikov 很公平,添加了免责声明
【解决方案2】:

由于在您的问题中只有 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

【讨论】:

    【解决方案3】:

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

    np.subtract(a, b):0.18578505516052246

    tuple(x - y for x, y in zip(a, b)) : 0.09348797798156738

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

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

    运算符对我来说看起来更优雅。

    【讨论】:

    • 你绝对不应该使用 np.subtract 如果你正在转换到和从 numpy 数组,但如果你正在做很多这些并且可以将它们保持在更合理的数据结构中任务!
    【解决方案4】:

    我的逐元素元组算术助手

    支持的操作:+、-、/、*、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 ))")
    

    【讨论】:

      【解决方案5】:

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

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

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

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

      【讨论】:

        【解决方案6】:

        使用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.
        

        【讨论】:

        • 感谢您的详细解答!
        • 请注意 izip:在 Python 3 中,常规 zip 函数的工作方式与 Python 2 的 izip 一样,因此您可以使用 zip 作为此答案中的示例.
        【解决方案7】:

        如果你想要快速,你可以使用 numpy:

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

        如果你想把它保存在一个元组中:

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

        【讨论】:

          【解决方案8】:

          一种选择是,

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

          itertools.imap 可以替代map

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-03-29
            • 2012-08-11
            • 1970-01-01
            • 1970-01-01
            • 2012-06-19
            • 1970-01-01
            • 2012-02-26
            • 2014-11-03
            相关资源
            最近更新 更多