【问题标题】:Element-wise addition of 2 lists?按元素添加 2 个列表?
【发布时间】:2013-09-13 19:59:05
【问题描述】:

我现在有:

list1 = [1, 2, 3]
list2 = [4, 5, 6]

我希望拥有:

[1, 2, 3]
 +  +  +
[4, 5, 6]
|| || ||
[5, 7, 9]

只需按元素添加两个列表。

我当然可以迭代这两个列表,但我不想这样做。

最 Pythonic 的方式是什么?

【问题讨论】:

标签: python list elementwise-operations


【解决方案1】:

mapoperator.add 一起使用:

>>> from operator import add
>>> list( map(add, list1, list2) )
[5, 7, 9]

zip 与列表理解:

>>> [sum(x) for x in zip(list1, list2)]
[5, 7, 9]

时序对比:

>>> list2 = [4, 5, 6]*10**5
>>> list1 = [1, 2, 3]*10**5
>>> %timeit from operator import add;map(add, list1, list2)
10 loops, best of 3: 44.6 ms per loop
>>> %timeit from itertools import izip; [a + b for a, b in izip(list1, list2)]
10 loops, best of 3: 71 ms per loop
>>> %timeit [a + b for a, b in zip(list1, list2)]
10 loops, best of 3: 112 ms per loop
>>> %timeit from itertools import izip;[sum(x) for x in izip(list1, list2)]
1 loops, best of 3: 139 ms per loop
>>> %timeit [sum(x) for x in zip(list1, list2)]
1 loops, best of 3: 177 ms per loop

【讨论】:

  • 如果你使用那些巨大的数组,@BasSwinckels 的 numpy 解决方案可能是你应该看看的东西。
  • 你用什么 Python 版本来计算这些时间?
  • 注: - 在 python3 中,map() 返回一个可迭代的东西而不是一个列表。如果您确实需要一个实际列表,第一个答案是 list(map(add, list1, list2))
  • 注意到@FLHerne 用map 指出的python3 问题会随着时间的推移变得越来越重要。 Python 2 将在不到 3 年内失去官方支持。
  • 很多时候,python 语法确实优雅而简单,但不幸的是,这不是其中之一。而对于这样一个简单的任务,实在是太可惜了……既然已经有了 .extend() 方法,为什么还要用“+”来连接列表呢?
【解决方案2】:

其他人给出了如何在纯 python 中执行此操作的示例。如果您想对具有 100.000 个元素的数组执行此操作,则应使用 numpy:

In [1]: import numpy as np
In [2]: vector1 = np.array([1, 2, 3])
In [3]: vector2 = np.array([4, 5, 6])

现在进行元素加法就像

一样简单
In [4]: sum_vector = vector1 + vector2
In [5]: print sum_vector
[5 7 9]

就像在 Matlab 中一样。

与 Ashwini 的最快版本进行比较的时机:

In [16]: from operator import add
In [17]: n = 10**5
In [18]: vector2 = np.tile([4,5,6], n)
In [19]: vector1 = np.tile([1,2,3], n)
In [20]: list1 = [1,2,3]*n
In [21]: list2 = [4,5,6]*n
In [22]: timeit map(add, list1, list2)
10 loops, best of 3: 26.9 ms per loop

In [23]: timeit vector1 + vector2
1000 loops, best of 3: 1.06 ms per loop

所以这快了 25 倍!但使用适合您情况的。对于一个简单的程序,你可能不想安装 numpy,所以使用标准的 python(我发现 Henry's version 是最 Pythonic 的)。如果您正在认真处理数字,请让numpy 完成繁重的工作。对于速度怪胎:从n = 8 开始,numpy 解决方案似乎更快。

【讨论】:

    【解决方案3】:
    [a + b for a, b in zip(list1, list2)]
    

    【讨论】:

    • @deltab 接受的答案更快并且它包含这个答案(更多信息)
    • @perfectm1ng 虽然我理解你的观点(并且一点也不吝啬)我只是认为值得指出的是,我将始终使用我提出的解决方案(鉴于它不需要import 可以说是最简单的,也可以说是更 Pythonic),或者在速度很重要的地方,Bas Swinckel 的答案,在速度很重要的情况下,这绝对是正确的选择。
    • 是的。感谢您的意见。但基本上[sum(x) for x in zip(list1, list2)] 与您的答案相同,不是吗? :)
    • @perfectm1ng 或多或少(尽管它是在我的编辑之后添加的:)。就个人而言,我更喜欢带有显式元组解包的 a+b 表示法,以提高可读性和 Python 性。
    【解决方案4】:

    正如其他人所描述的,一个快速且节省空间的解决方案是使用 numpy (np) 及其内置的向量操作功能:

    1.使用 Numpy

    x = np.array([1,2,3])
    y = np.array([2,3,4])
    print x+y
    

    2。内置插件

    2.1 Lambda

    list1=[1, 2, 3]
    list2=[4, 5, 6]
    print map(lambda x,y:x+y, list1, list2)
    

    注意 map() 支持多个参数。

    2.2 压缩和列表理解

    list1=[1, 2, 3]
    list2=[4, 5, 6]
    print [x + y for x, y in zip(list1, list2)]
    

    【讨论】:

    • +1 用于 lambda 方法。很遗憾,该解决方案与其他地方重复的其他解决方案相结合。
    【解决方案5】:

    在我看来,使用numpy 更简单:

    import numpy as np
    list1=[1,2,3]
    list2=[4,5,6]
    np.add(list1,list2)
    

    结果:

    详细参数信息请看这里:numpy.add

    【讨论】:

      【解决方案6】:

      如果您有未知数量的列表并且不导入任何内容,这可能是 pythonic 并且稍微有用。

      只要列表长度相同,就可以使用下面的函数。

      这里的 *args 接受可变数量的列表参数(但每个参数的总和数量相同)。

      在返回的列表中再次使用 * 来解包每个列表中的元素。

      def sum_lists(*args):
          return list(map(sum, zip(*args)))
      
      a = [1,2,3]
      b = [1,2,3]  
      
      sum_lists(a,b)
      

      输出:

      [2, 4, 6]
      

      或者有 3 个列表

      sum_lists([5,5,5,5,5], [10,10,10,10,10], [4,4,4,4,4])
      

      输出:

      [19, 19, 19, 19, 19]
      

      【讨论】:

        【解决方案7】:

        也许“最pythonic的方式”应该包括处理list1和list2大小不同的情况。应用其中一些方法会悄悄地给你答案。 numpy 方法会让你知道,很可能会出现 ValueError。

        例子:

        import numpy as np
        >>> list1 = [ 1, 2 ]
        >>> list2 = [ 1, 2, 3]
        >>> list3 = [ 1 ]
        >>> [a + b for a, b in zip(list1, list2)]
        [2, 4]
        >>> [a + b for a, b in zip(list1, list3)]
        [2]
        >>> a = np.array (list1)
        >>> b = np.array (list2)
        >>> a+b
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        ValueError: operands could not be broadcast together with shapes (2) (3)
        

        如果这是在您的问题中的函数中,您可能想要什么结果?

        【讨论】:

        【解决方案8】:

        这很简单 numpy.add()

        import numpy
        
        list1 = numpy.array([1, 2, 3])
        list2 = numpy.array([4, 5, 6])
        result = numpy.add(list1, list2) # result receive element-wise addition of list1 and list2
        print(result)
        array([5, 7, 9])
        

        See doc here

        如果你想接收一个 python 列表:

        result.tolist()
        

        【讨论】:

          【解决方案9】:

          这适用于 2 个或更多列表;遍历列表列表,但使用 numpy 加法处理每个列表的元素

          import numpy as np
          list1=[1, 2, 3]
          list2=[4, 5, 6]
          
          lists = [list1, list2]
          list_sum = np.zeros(len(list1))
          for i in lists:
             list_sum += i
          list_sum = list_sum.tolist()    
          
          [5.0, 7.0, 9.0]
          

          【讨论】:

            【解决方案10】:

            如果您需要处理不同大小的列表,请不要担心!精彩的itertools 模块为您提供:

            >>> from itertools import zip_longest
            >>> list1 = [1,2,1]
            >>> list2 = [2,1,2,3]
            >>> [sum(x) for x in zip_longest(list1, list2, fillvalue=0)]
            [3, 3, 3, 3]
            >>>
            

            在 Python 2 中,zip_longest 被称为 izip_longest

            另见this relevant answer and comment on another question

            【讨论】:

              【解决方案11】:
              [list1[i] + list2[i] for i in range(len(list1))]
              

              【讨论】:

              • 更多pythonic将是[a + b for (a, b) in zip(list1, list2)]
              • @rayryeng 或者没有括号:[a + b for a, b in zip(list1, list2)]
              【解决方案12】:

              使用带有 lambda 函数的地图:

              >>> map(lambda x, y: x + y, list1, list2)
              [5, 7, 9]
              

              【讨论】:

                【解决方案13】:

                我还没有计时,但我怀疑这会很快:

                import numpy as np
                list1=[1, 2, 3]
                list2=[4, 5, 6]
                
                list_sum = (np.add(list1, list2)).tolist()
                
                [5, 7, 9]
                

                【讨论】:

                  【解决方案14】:

                  虽然实际问题不想遍历列表来生成结果,但所有提出的解决方案都在幕后完成了!

                  要刷新:如果不查看所有向量元素,就无法添加两个向量。因此,大多数这些解决方案的算法复杂度都是 Big-O(n)。其中n是向量的维数。

                  因此,从算法的角度来看,使用 for 循环迭代生成结果列表也是合乎逻辑且符合 Python 的。但是,此外,此方法没有调用或导入任何额外库的开销。

                  # Assumption: The lists are of equal length.
                  resultList = [list1[i] + list2[i] for i in range(len(list1))]
                  

                  此处显示/讨论的时间取决于系统和实施,不能作为衡量操作效率的可靠措施。无论如何,向量加法运算的大 O 复杂度是线性的,即 O(n)。

                  【讨论】:

                    【解决方案15】:
                    • zip 函数在这里很有用,与列表理解 v1v2 一起使用。
                    • 如果您有一个列表列表(而不仅仅是两个列表),您可以使用v3
                    • 对于不同长度的列表(例如:通过在第一个/第二个列表的末尾添加 1),那么您可以尝试这样的事情(使用 zip_longest)-v4
                    first = [1, 2, 3, 1]
                    second = [4, 5, 6]
                    
                    output: [5, 7, 9, 1]
                    
                    • 如果你有未知数量的相同长度的列表,你可以使用函数v5

                    • v6 - 运算符模块导出一组与 Python 的内在运算符相对应的高效函数。例如,operator.add(x, y) 等价于表达式x+y

                    • v7 - 假设两个列表 firstsecond 具有相同的长度,您不需要 zip 或其他任何东西。

                    ################
                    first = [1, 2, 3]
                    second = [4, 5, 6]
                    
                    ####### v1 ########
                    third1 = [sum(i) for i in zip(first,second)]
                    
                    ####### v2 ########
                    third2 = [x + y for x, y in zip(first, second)]
                    
                    ####### v3 ########
                    lists_of_lists = [[1, 2, 3], [4, 5, 6]]
                    third3 = [sum(x) for x in zip(*lists_of_lists)]
                    
                    ####### v4 ########
                    from itertools import zip_longest
                    third4 = list(map(sum, zip_longest(first, second, fillvalue=0)))
                    
                    ####### v5 ########
                    def sum_lists(*args):
                        return list(map(sum, zip(*args)))
                    
                    third5 = sum_lists(first, second)
                    
                    ####### v6 ########
                    import operator
                    third6 = list(map(operator.add, first,second))
                    
                    ####### v7 ########
                    third7 =[first[i]+second[i] for i in range(len(first))]
                    
                    ####### v(i) ########
                    
                    print(third1) # [5, 7, 9]
                    print(third2) # [5, 7, 9]
                    print(third3) # [5, 7, 9]
                    print(third4) # [5, 7, 9]
                    print(third5) # [5, 7, 9]
                    print(third6) # [5, 7, 9]
                    print(third7) # [5, 7, 9]
                    

                    【讨论】:

                    • 点评来源: Stack Overflow 上不鼓励仅使用代码的答案,因为它们没有解释它是如何解决问题的。请编辑您的答案以解释此代码的作用以及它如何回答问题,以便它对 OP 以及其他也有类似问题的用户有用。请参阅:How do I write a good answer?。谢谢
                    【解决方案16】:
                    a_list = []
                    b_list = []
                    for i in range(1,100):
                        a_list.append(random.randint(1,100))
                    
                    for i in range(1,100):
                        a_list.append(random.randint(101,200))
                    [sum(x) for x in zip(a_list , b_list )]
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-11-09
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-02-11
                      • 2017-08-30
                      • 1970-01-01
                      相关资源
                      最近更新 更多