【问题标题】:Adding Values From Tuples of Same Length从相同长度的元组中添加值
【发布时间】:2009-07-23 05:15:44
【问题描述】:

在我使用 pygame 编写的图形程序中,我使用一个表示坐标的元组,如下所示:(50, 50)。

有时,我调用一个函数,它返回另一个元组,例如 (3, -5),它表示坐标的变化。

将更改值添加到坐标值的最佳方法是什么。如果我能做一些类似坐标 += 改变的事情会很好,但看起来这会简单地将两个元组连接到 (50, 50, 3, -5) 之类的东西。而不是将第一个值与第一个值相加,将第二个值与第二个相加,并返回一个结果元组。

到目前为止,我一直在使用这种相当烦人的方法: coord = (coord[0] + change[0], coord[1] + change[1])

有什么更好、更简洁的方法将两个相同长度的元组的值相加。如果元组是任意长度或特别长的长度会使以前的方法更加烦人,那么知道如何做似乎尤为重要。

【问题讨论】:

    标签: python


    【解决方案1】:

    嗯,一种方法是

    coord = tuple(sum(x) for x in zip(coord, change))
    

    如果您进行大量数学运算,您可能需要使用 NumPy 进行调查,它具有更强大的数组支持和更好的性能。

    【讨论】:

      【解决方案2】:

      列表推导式可能更具可读性,但这是另一种方式:

      >>> a = (1,2)
      >>> b = (3,4)
      >>> tuple(map(sum,zip(a,b)))
      (4,6)
      

      【讨论】:

      • 我碰巧发现理解/生成器表达式更具可读性,但我敢肯定,头脑工作更“轻松”的人会发现地图解决方案更清晰。
      • 我自己也很口齿不清,但更喜欢列表推导式,因为 Haskell 也与我的思维方式相去甚远。
      • 这是实际需要的 zip:>>> from operator import add >>> a = (1, 2) >>> b = (3, 4) >>> tuple(map(加, a, b)) (4, 6) >>>
      【解决方案3】:

      正如 John Y 所说,使用 numpy 非常容易。

      import numpy as np
      
      x1 = (0,3)
      x2 = (4,2)
      tuple(np.add(x1,x2))
      

      【讨论】:

      • 唯一明白的答案,当他们说“简洁方法”时,OP 的意思是什么
      【解决方案4】:

      这是一项正在进行的工作,因为我自己也在学习 Python。我们可以在这里使用类吗,以后可以简化一些操作。我建议使用坐标类来存储坐标。它将覆盖 add 和 sub,因此您可以通过简单地使用运算符 + 和 - 来进行加法和减法。您可以使用内置函数获得元组表示。

      class coord(object):    
          def __init__(self,x,y):
              self.x = x
              self.y = y
      
          def __add__(self,c):
              return coord(self.x + c.x, self.y + c.y)
      
          def __sub__(self,c):
              return coord(self.x - c.x, self.y - c.y)
      
          def __eq__(self,c): #compares two coords
              return self.x == c.x and self.y == c.y
      
          def t(self): #return a tuple representation.
              return (self.x,self.y)
      

      用法

      c1 = coord(4,3) #init coords
      c2 = coord(3,4)
      
      c3 = c1 + c2    #summing two coordinates. calls the overload __add__
      print c3.t()    #prints (7, 7)
      c3 = c3 - c1
      print c3.t()    #prints (3, 4)
      print c3 == c2  #prints True
      

      您也可以改进坐标以扩展其他运算符(小于、大于 ..)。

      在这个版本中,在完成计算之后,您可以通过说 coord.t() 来调用期望元组的 pygame 方法。不过,可能有比使用函数返回元组形式更好的方法。

      【讨论】:

        【解决方案5】:

        要获得您的“+”和“+=”行为,您可以定义自己的类并实现__add__() 方法。以下是不完整的样本:

        # T.py
        class T(object):
            def __init__(self, *args):
                self._t = args
            def __add__(self, other):
                return T(*([sum(x) for x in zip(self._t, other._t)]))
            def __str__(self):
                return str(self._t)
            def __repr__(self):
                return repr(self._t)
        
        >>> from T import T
        >>> a = T(50, 50)
        >>> b = T(3, -5)
        >>> a
        (50, 50)
        >>> b
        (3, -5)
        >>> a+b
        (53, 45)
        >>> a+=b
        >>> a
        (53, 45)
        >>> a = T(50, 50, 50)
        >>> b = T(10, -10, 10)
        >>> a+b
        (60, 40, 60)
        >>> a+b+b
        (70, 30, 70)
        

        编辑:我找到了更好的方法...

        将类 T 定义为元组的子类并覆盖 __new____add__ 方法。这提供了与tuple 类相同的接口(但__add__ 具有不同的行为),因此可以将类 T 的实例传递给任何需要元组的对象。

        class T(tuple):
            def __new__(cls, *args):
                return tuple.__new__(cls, args)
            def __add__(self, other):
                return T(*([sum(x) for x in zip(self, other)]))
            def __sub__(self, other):
                return self.__add__(-i for i in other)
        
        >>> a = T(50, 50)
        >>> b = T(3, -5)
        >>> a
        (50, 50)
        >>> b
        (3, -5)
        >>> a+b
        (53, 45)
        >>> a+=b
        >>> a
        (53, 45)
        >>> a = T(50, 50, 50)
        >>> b = T(10, -10, 10)
        >>> a+b
        (60, 40, 60)
        >>> a+b+b
        (70, 30, 70)
        >>> 
        >>> c = a + b
        >>> c[0]
        60
        >>> c[-1]
        60
        >>> for x in c:
        ...     print x
        ... 
        60
        40
        60
        

        【讨论】:

        • 你仍然需要一个函数来从你的类型 T 转换为一个元组不是。因为你不能使用 a+b 代替你需要一个元组的地方。它将返回一个 T 类型的实例。
        • @Sizzler:我认为“新”版本解决了您的担忧。
        • 这很酷,我会通过使用zip_longest(否则如果将短向量添加到长向量会丢失信息)和更改repr(因为它仍然与元组不同)来使它变得更好。另外,你根本不需要定义__new__,只需定义__init__
        • @ilya n: __new__ 被覆盖提供与tuple 相同的对象创建接口,否则无法通过t = T(1,2,3) 创建实例。例如尝试class T(tuple): pass,然后t = T(1,2,3) 会给你TypeError: tuple() takes at most 1 argument (3 given)。见docs.python.org/reference/datamodel.html#object.__new__
        • 这些例子有些误导。当您执行a+=b 时,您通常期望a 是同一个对象(除非文档明确声明不可变性)。所以你可以轻松实现__iadd__/__isub__。话虽这么说,元组确实是不可变的,所以我不确定还有什么是 Pythonic 的。
        【解决方案6】:

        我的两分钱,希望对你有帮助

        >>> coord = (50, 50)
        >>> change = (3, -5)
        >>> tuple(sum(item) for item in zip(coord, change))
        (53, 45)
        

        【讨论】:

        • 这是我会使用的,但如果你格式化它会更清楚。您的答案比 Unknown 的更笼统,但应该像他/她的一样格式化。
        • @John,对不起,我的错。我只是在单击按钮之前插入第一行,也许它破坏了格式。 @Triptych,谢谢!
        猜你喜欢
        • 2017-12-03
        • 2022-07-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-09
        • 1970-01-01
        • 1970-01-01
        • 2021-12-07
        相关资源
        最近更新 更多