110

Right now I have vector3 values represented as lists. is there a way to subtract 2 of these like vector3 values, like

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

Should I use tuples?

If none of them defines these operands on these types, can I define it instead?

If not, should I create a new vector3 class?

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
Joan Venge
  • 315,713
  • 212
  • 479
  • 689

16 Answers16

162

If this is something you end up doing frequently, and with different operations, you should probably create a class to handle cases like this, or better use some library like Numpy.

Otherwise, look for list comprehensions used with the zip builtin function:

[a_i - b_i for a_i, b_i in zip(a, b)]
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
UncleZeiv
  • 18,272
  • 7
  • 49
  • 77
91

Here's an alternative to list comprehensions. Map iterates through the list(s) (the latter arguments), doing so simulataneously, and passes their elements as arguments to the function (the first arg). It returns the resulting list.

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

This code because has less syntax (which is more aesthetic for me), and apparently it's 40% faster for lists of length 5 (see bobince's comment). Still, either solution will work.

Maziyar
  • 1,913
  • 2
  • 18
  • 37
Nikhil
  • 5,705
  • 1
  • 32
  • 30
  • I usually see list comprehensions being recomemnded over map(), although that may just be because it's cleaner-looking code... not sure about the performance difference, if any. – David Z Feb 11 '09 at 00:50
  • 2
    The map() comes out almost 40% faster for me on Py2.6 for a five-element subtraction. Comprehensions are newer and cleaner where they avoid a lambda, but for mapping existing functions map can still be pretty... especially here where you can leverage the built-in zip. – bobince Feb 11 '09 at 01:07
  • 1
    this also works for array.array (although the result is a list) – gens Oct 20 '16 at 20:53
  • 6
    'import operator' clause is needed; int.__sub__ does the trick better )) – garej Apr 09 '17 at 05:30
  • 1
    In order to print the contents you could write `print(list(map(operator.sub, a, b)))`. – amc Nov 14 '21 at 00:02
18

If your lists are a and b, you can do:

map(int.__sub__, a, b)

But you probably shouldn't. No one will know what it means.

recursive
  • 83,943
  • 34
  • 151
  • 241
  • 2
    Ran into this myself with floats. In which case `map(float.__sub__, a, b)` works. Thanks for the tip! – S3DEV Apr 16 '19 at 14:04
  • Hi, is it faster than `import operator map(operator.sub, a, b)`? – zheyuanWang Jul 01 '21 at 05:46
  • 1
    recursive: I actually wanted to use it so I simply aliased it with "subtract = int.__sub__" in a LOCAL scope, to avoid bringing in "operator" and make it read clearly. I really don't think it's bad that way. @zheyuanWang marginally faster at best. I didn't do real timings but was working a problem at leetcode and it was as fast as anything else, maybe a bit faster (but those numbers jump around a lot.) – HerbM Aug 11 '21 at 06:24
17
import numpy as np
a = [2,2,2]
b = [1,1,1]
np.subtract(a,b)
user3503711
  • 1,623
  • 1
  • 21
  • 32
13

I'd have to recommend NumPy as well

Not only is it faster for doing vector math, but it also has a ton of convenience functions.

If you want something even faster for 1d vectors, try vop

It's similar to MatLab, but free and stuff. Here's an example of what you'd do

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

Boom.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
mikelikespie
  • 5,682
  • 3
  • 31
  • 36
7

If you have two lists called 'a' and 'b', you can do: [m - n for m,n in zip(a,b)]

Andy Mikula
  • 16,796
  • 4
  • 32
  • 39
6

Many solutions have been suggested.

If speed is of interest, here is a review of the different solutions with respect to speed (from fastest to slowest)

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)

Using map is clearly the fastest. Surprisingly, numpy is the slowest. It turns out that the cost of first converting the lists a and b to a numpy array is a bottleneck that outweighs any efficiency gains from vectorization.

%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)
ProteinGuy
  • 1,754
  • 2
  • 17
  • 33
4

A slightly different Vector class.

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)
S.Lott
  • 384,516
  • 81
  • 508
  • 779
3

For the one who used to code on Pycharm, it also revives others as well.

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

If you plan on performing more than simple one liners, it would be better to implement your own class and override the appropriate operators as they apply to your case.

Taken from Mathematics in 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
codelogic
  • 71,764
  • 9
  • 59
  • 54
2

The combination of map and lambda functions in Python is a good solution for this kind of problem:

a = [2,2,2]
b = [1,1,1]
map(lambda x,y: x-y, a,b)

zip function is another good choice, as demonstrated by @UncleZeiv

BioCoder
  • 597
  • 1
  • 5
  • 14
1

This answer shows how to write "normal/easily understandable" pythonic code.

I suggest not using zip as not really everyone knows about it.


The solutions use list comprehensions and common built-in functions.


Alternative 1 (Recommended):

a = [2, 2, 2]
b = [1, 1, 1]
result = [a[i] - b[i] for i in range(len(a))]

Recommended as it only uses the most basic functions in Python


Alternative 2:

a = [2, 2, 2]
b = [1, 1, 1]
result = [x - b[i] for i, x in enumerate(a)]

Alternative 3 (as mentioned by BioCoder):

a = [2, 2, 2]
b = [1, 1, 1]
result = list(map(lambda x, y: x - y, a, b))
Timmy Chan
  • 933
  • 7
  • 15
0
arr1=[1,2,3]
arr2=[2,1,3]
ls=[arr2-arr1 for arr1,arr2 in zip(arr1,arr2)]
print(ls)
>>[1,-1,0]
ravi tanwar
  • 598
  • 5
  • 16
  • 2
    While this code snippet may be the solution, [including an explanation](https://meta.stackexchange.com/questions/114762/explaining-entirely-%E2%80%8C%E2%80%8Bcode-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Narendra Jadhav Jul 21 '18 at 05:55
0

Very easy

list1=[1,2,3,4,5]
list2=[1,2]
list3=[]
# print(list1-list2)

for element in list1:
    if element not in list2:
       list3.append(element)

print(list3)
Aniket Malik
  • 165
  • 1
  • 10
0

use a for loop

a = [3,5,6]
b = [3,7,2]

c = []

for i in range(len(a)):
     c.append(a[i] - b[i])

print(c)

output [0, -2, 4]

Golden Lion
  • 3,840
  • 2
  • 26
  • 35
-1

Try this:

list(array([1,2,3])-1)
Rostyslav Dzinko
  • 39,424
  • 5
  • 49
  • 62