用Python求两个列表的差集

112

现在我有用列表表示的vector3值。是否有一种像vector3值一样减去其中2个的方法,例如

[2,2,2] - [1,1,1] = [1,1,1]

我应该使用元组吗?

如果没有定义这些类型的这些操作数,我可以自己定义吗?

如果不行,我应该创建一个新的vector3类吗?

16个回答

163
如果这是您经常需要做的事情,并且有不同的操作方式,那么您应该创建一个类来处理这种情况,或者更好地使用一些库,例如Numpy

否则,可以寻找与zip内置函数一起使用的列表理解

[a_i - b_i for a_i, b_i in zip(a, b)]

91

这里有一个替代列表推导式的方法。Map函数同时迭代列表(后面的参数),并将它们的元素作为参数传递给函数(第一个参数)。它返回生成的列表。

import operator
map(operator.sub, a, b)

这段代码因为语法少(更美观),而且对于长度为5的列表来说显然快了40%(请参见bobince的评论)。 不过,两种解决方案都能工作。


我通常看到人们推荐使用列表推导式而不是map(),尽管这可能只是因为代码更简洁漂亮...如果有性能差异,我并不确定。 - David Z
2
map() 在 Py2.6 上对于五个元素的减法可以快近 40%。Comprehensions 更加新且更干净,尤其是在避免使用 lambda 表达式时,但对于映射现有函数,map 仍然非常有效... 特别是在这里,您可以利用内置的 zip 函数。 - bobince
1
这对于 array.array 也适用(尽管结果是一个列表)。 - gens
6
需要添加 'import operator' 语句;使用 int.sub 更好地实现了这一点)) - garej
1
为了打印内容,您可以编写print(list(map(operator.sub, a, b))) - amc

18

如果你的列表是a和b,你可以这样做:

map(int.__sub__, a, b)

不过你可能不应该这样做。没有人会知道它的意思。


2
我自己在使用浮点数时也遇到了这个问题。此时,map(float.__sub__, a, b) 可以解决问题。感谢您的提示! - S3DEV
你好,这比 import operator map(operator.sub, a, b) 更快吗? - zheyuanWang
1
递归:我实际上想使用它,所以我在LOCAL作用域中使用别名"subtract = int.sub",以避免引入"operator"并使它更清晰易读。我真的不认为这样做有什么不好。@zheyuanWang 最好只能稍微快一点点。我没有进行真正的计时,但当我在LeetCode上尝试一个问题时,它和其他任何方法一样快,甚至可能更快一些(但这些数字经常波动). - HerbM

17
import numpy as np
a = [2,2,2]
b = [1,1,1]
np.subtract(a,b)

13

我还要推荐NumPy

不仅在进行矢量数学运算时更快,而且它还有很多方便的函数。

如果你想要更快速地处理一维向量,可以尝试vop

它类似于MatLab,但是免费的。这里是一个示例:

from numpy import matrix
a = matrix((2,2,2))
b = matrix((1,1,1))
ret = a - b
print ret
>> [[1 1 1]]

嘭。


1
np.array 将是一个更简单的解决方案。 - garej

7
如果你有两个名为'a'和'b'的列表,你可以这样做:[m - n for m,n in zip(a,b)]

6

已经提出了许多解决方案。

如果速度很重要,这里是对不同解决方案在速度方面的评估(从最快到最慢)

import timeit
import operator

a = [2,2,2]
b = [1,1,1]  # we want to obtain c = [2,2,2] - [1,1,1] = [1,1,1

%timeit map(operator.sub, a, b)
176 ns ± 7.18 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit map(int.__sub__, a, b)
179 ns ± 4.95 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit map(lambda x,y: x-y, a,b)
189 ns ± 8.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit [a_i - b_i for a_i, b_i in zip(a, b)]
421 ns ± 18.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit [x - b[i] for i, x in enumerate(a)]
452 ns ± 17.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each

%timeit [a[i] - b[i] for i in range(len(a))]
530 ns ± 16.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit list(map(lambda x, y: x - y, a, b))
546 ns ± 16.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit np.subtract(a,b)
2.68 µs ± 80.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit list(np.array(a) - np.array(b))
2.82 µs ± 113 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit np.matrix(a) - np.matrix(b)
12.3 µs ± 437 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

使用map显然是最快的。 令人惊讶的是,numpy是最慢的。原来将列表ab首先转换为numpy数组的代价是一个瓶颈,超过了向量化带来的任何效率收益。

%timeit a = np.array([2,2,2]); b=np.array([1,1,1])
1.55 µs ± 54.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

a = np.array([2,2,2])
b = np.array([1,1,1])
%timeit a - b
417 ns ± 12.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

4
一个略有不同的向量类。
class Vector( object ):
    def __init__(self, *data):
        self.data = data
    def __repr__(self):
        return repr(self.data) 
    def __add__(self, other):
        return tuple( (a+b for a,b in zip(self.data, other.data) ) )  
    def __sub__(self, other):
        return tuple( (a-b for a,b in zip(self.data, other.data) ) )

Vector(1, 2, 3) - Vector(1, 1, 1)

3

对于那些曾经在Pycharm上编程的人来说,它也会使其他人复苏。

 import operator
 Arr1=[1,2,3,45]
 Arr2=[3,4,56,78]
 print(list(map(operator.sub,Arr1,Arr2)))

3
如果您计划执行的不仅仅是简单的一行代码,那么最好实现自己的类并覆盖适用于您情况的相应运算符。
来自Python中的数学
class Vector:

  def __init__(self, data):
    self.data = data

  def __repr__(self):
    return repr(self.data)  

  def __add__(self, other):
    data = []
    for j in range(len(self.data)):
      data.append(self.data[j] + other.data[j])
    return Vector(data)  

x = Vector([1, 2, 3])    
print x + x

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接