Finding the sum of matching components in two lists - python

I have two lists:
A = [1, 2, 3, 4, 5]
B = [6, 7, 8, 9, 10]
And I need to be able to find the sum of the nth terms from both lists i.e. 1+6, 2+7, 3+8 etc
Could someone please tell me how to refer to items in both lists at the same time?
I read somewhere that I could do Sum = a[i] + b[i] but I'm not convinced on how that would work.

>>> import operator
>>> map(operator.add, A, B)
[7, 9, 11, 13, 15]
just to demonstrate Pythons elegance :-)

Use a list comprehension and zip:
[a + b for (a,b) in zip(A,B)]
Are these questions homework? Or self-study?

If you know the lists will be the same length, you could do this:
AB = [A[i] + B[i] for i in range(len(A))]
In Python 2, you might want to use xrange instead of range if your lists are quite large. I think that's an explicit, simple, readable, obvious way to do it, but some might differ.
If the lists might be different lengths, you have to decide how you want to handle the extra elements. Let's say you want to ignore the extra elements of whichever list is longer. Here are three ways to do it:
AB = [A[i] + B[i] for i in range(min(len(A), len(B)))]
AB = map(sum, zip(A, B))
AB = [a + b for a, b in zip(A, B)]
The downside of using zip is that it will allocate a list of tuples, which can be a lot of memory if your lists are already large. Using for i in xrange with subscripting won't allocate all that memory, or you can use itertools.izip:
import itertools
AB = map(sum, itertools.izip(A, B))
If you instead want to pretend the shorter list is padded with zeros, using itertools.izip_longest is the shortest answer:
import itertools
AB = map(sum, itertools.izip_longest(A, B, fillvalue=0))
or
import itertools
AB = [a + b for a, b in itertools.izip_longest(A, B, fillvalue=0)]

Although Jazz's solution works for 2 lists, what if you have more than 2 lists? Here's a solution:
def apply_elementwise_function(elements_in_iterables, function):
elementwise_function = lambda x, y: itertools.imap(function, itertools.izip(x, y))
return reduce(elementwise_function, elements_in_iterables)
a = b = c = [1, 2, 3]
>>> list(apply_elementwise_function([a, b, c], sum))
[3, 6, 9]

Hi You can try this too:
>>>a=[1,2,3,4,5]
>>>b=[6,7,8,9,10]
>>>c=[]
>>>for i in range(0,5):
c.append(a[i]+b[i])
>>> c
[7, 9, 11, 13, 15]

Related

How to add integers together in two matrices using the zip() function in Python

I cannot figure out how to add integers together in two matrices using the zip() function. Here is what I have:
matrix_a = [[3,6],[4,5]]
matrix_b = [[5,8],[6,7]]
I need to print out (using zip()):
[[8,14],[10,12]]
The following list comprehension will do the trick:
>>> [[x + y for x, y in zip(a, b)] for a, b in zip(matrix_a, matrix_b)]
[[8, 14], [10, 2]]
If you want the version that uses loops:
result = []
for a, b in zip(matrix_a, matrix_b):
current_list = []
for x, y in zip(a, b):
current_list.append(x + y)
result.append(current_list)
>>> result
[[8, 14], [10, 2]]
However, I definitely like more the comprehension version it is easier to read.

Apply a function with lists like inputs

I want to create a new list (V) from other lists (a, b, c) and using a function, but I would like to take advantage of python and apply the function to the three lists and not element by element.
For example, I have the lists a, b and c; and the result after apply the function should be V. Thanks.
def mag(a, b, c):
# something sophisticated
return (a+b)*c
a = [1, 5, 7]
b = [4, 8, 3]
c = [2, 6, 3]
V = [10, 78, 30]
You can easily do this with the map function:
V = list(map(mag, a, b, c))
You want to first zip the arguments, then map the function on the unpacked tuples:
from itertools import starmap
starmap(mag, zip(a,b,c))
See here for an example.
An alternate solution is to use map and lambda
In [16]: list(map(lambda p: mag(*p), zip(a, b, c)))
Out[16]: [10, 78, 30]
What about using only built-in functions? Like zip
>>> [mag(a_, b_, c_) for a_,b_,c_ in zip(a, b, c)]
[10, 78, 30]
Plus another python buit-in function, map which returns an
iterator and thus makes things go faster and ends up saving memory:
>>> gen = map(lambda uple:mag(*uple), zip(a, b, c))
>>> list(gen)
[10, 78, 30]

How to refer to next element in a loop?

I've been looking around for this but can't find what I would like to. I'm sure I've seen this done before but I can't seem to find it. Here's an example:
In this case I would like to take the difference of each element in an array,
#Generate sample list
B = [a**2 for a in range(10)]
#Take difference of each element
C = [(b+1)-b for b in B]
the (b+1) is to denote the next element in the array which I don't know how to do and obviously doesn't work, giving the result:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
the result I would like is:
[1, 3, 5, 7, 9, 11, 13, 15, 17]
I understand that this result is shorter than the original array however the reason for this would be to replace ugly expressions such as:
C = [B[i+1]-B[i] for i in range(len(B)-1)]
In this case it really isn't that bad at all, but there are cases that I need to iterate through multiple variables with long expressions and it gets annoying to keep having to write the index in each time. Right now I'm hoping that there is an easy pythonic way to do this that I don't know about...
EDIT: An example of what I mean about having to do this with multiple variables would be:
X = [a for a in range(10)]
Y = [a**2 for a in range(10)]
Z = [a**3 for a in range(10)]
for x,y,z in zip(X,Y,Z):
x + (x+1) + (y-(y+1))/(z-(z+1))
where (x+1),(y+1),(z+1) denote the next element rather than:
for i in range(len(X)):
x[i] + x[i+1] + (y[i]-y[i+1])/(z[i]-z[i+1])
I am using python 2.7.5 btw
re: your edit
zip is still the right solution. You just need to zip together two iterators over the lists, the second of which should be advanced one tick.
from itertools import izip,tee
cur,nxt = tee(izip(X,Y,Z))
next(nxt,None) #advance nxt iterator
for (x1,y1,z1),(x2,y2,z2) in izip(cur,nxt):
print x1 + x2 + (y1-y2)/(z1-z2)
If you don't like the inline next call, you can use islice like #FelixKling mentioned: izip(cur,islice(nxt, 1, None)).
Alternative you can use zip, to create tuples of the current value, next value:
C = [b - a for a, b in zip(B, B[1:])]
I believe zip returns a generator in Python 3. In Python 2, you might want to use izip. And B[1:], you could use islice: islice(B, 1, None).
Maybe you want enumerate. As follows:
C = [B[b+1]-item for b,item in enumerate(B[:-1])]
or simply:
C = [B[b+1]-B[b] for b in range(len(B[:-1]))]
They both work.
Examples
>>> B = [a**2 for a in range(10)]
>>> C = [B[b+1]-item for b,item in enumerate(B[:-1])]
>>> print C
[1, 3, 5, 7, 9, 11, 13, 15, 17]
This is a pretty weird way, but it works!
b = [a**2 for a in range(10)]
print b
print reduce(lambda x, y:len(x) and x[:-1]+[y-x[-1], y] or [y], b, [])
I have created a bunk on CodeBunk so you can run the it too
http://codebunk.com/b/-JJzLIA-KZgASR_3a-I8

Remove all occurences of a given value in multiple arrays at once

I have four arrays, say, A, B, C and D, of the same size NumElements, and I want to remove all the 0s in them. If A has a zero, B, C and D have one too, in the same position. So I was thinking to loop over the elements of A:
for n in range(NumElements):
if A[n]==0:
A.pop(n)
B.pop(n)
C.pop(n)
D.pop(n)
Of course, this doesn't work, because popping 0s from the arrays reduces their sizes, so I end up trying to access A[NumElements-1], when now A is only NumElements-m long. I know I should work with array copies, but the arrays are quite long and I'd like to keep memory consumption low, since I'm working in a Java virtual machine (don't ask :(((( ). Also, I'd like an approach which is efficient, but most of all readable (this code must be maintained by Python illiterates like me, so I need to KISS).
a,b,c,d = [filter(lambda i: i != 0, l) for l in [a,b,c,d]]
Filter each list removing elements that are not 0.
Edit,
Just to explain whats happening
Filter takes an expression and "filters" the list, by applying the function to everything in the list, everything that does not return True.
Lambda is a short hand for a function
So
a = [1,2,3,4,5,6,7,8]
def is_even(x):
return x % 2 == 0
filter(is_even, a)
If they all have zeros in the same place, then loop over the index in reverse and remove that index from each list:
for i in reversed(range(NumElements)):
if not A[i]:
del A[i], B[i], C[i], D[i]
By looping over the list in reverse, you keep the indices stable (only elements past the current index have been removed, shrinking only the tail of the lists). Since you are not using the return value of list.pop() (all you get is 0s anyway, right?), you may as well just use del on the list index instead.
I used reversed(range(NumElements)) here instead of calculating the more strenuous range(NumElements - 1, -1, -1); it is just as efficient but a lot more readable. The reversed() function returns an iterator, handling the reversed number sequence very efficiently. On Python 2, you can do the same with xrange():
for i in reversed(xrange(NumElements)):
Demo:
>>> A = [1, 2, 0, 4, 5, 0]
>>> B = [2, 4, 0, 10, 9, 0]
>>> C = [5, 3, 0, 10, 8, 0]
>>> D = [10, 3, 0, 1, 34, 0]
>>> for i in reversed(range(NumElements)):
... if not A[i]:
... del A[i], B[i], C[i], D[i]
...
>>> A, B, C, D
([1, 2, 4, 5], [2, 4, 10, 9], [5, 3, 10, 8], [10, 3, 1, 34])
Just work from the other end!
for n in range(NumElements-1,-1,-1):
if A[n]==0:
A.pop(n)
B.pop(n)
C.pop(n)
D.pop(n)
I think you could do smth like this. I don't know if it's pythonic enough.
A = [1, 2, 4, 0]
B = [6, 0, 4, 3, 9]
C = [12, 5, 32, 0, 90]
for row in [A, B, C]:
for i, v in enumerate(row):
if v == 0: del row[i]
or, if you sure that indexes of zero are equal in all lists:
for i in range(len(A) - 1, -1, -1):
if A[i] == 0:
for row in [A, B, C]:
del row[i]
Look at my other answer List accessing in Python. You can walk through list A and store indexes of 0s in temporary list and then pop them.
This is probably a hack but it's simple and it works
>>> a = [1,2,3]
>>> b = [1,10,99]
>>> c = [1,87,22]
>>> d = []
>>> d.extend([a,b,c])
>>> to_remove = 1
>>> [i.remove(to_remove) for i in d]
>>> d
[[2, 3], [10, 99], [87, 22]]
Note that this will remove all elements marked as to_remove not just zeros at the beginning, I'm assuming this is ok for you because you say that you want to remove all the zeros.

Simpler/preferred way to iterate over two equal-length lists and append the max of each pair to a new list?

Given two lists of equal length, is there a simpler or preferred way to iterate over two lists of equal length and append the maximum of each pair of elements to a new list? These are the two methods I know of.
import itertools
a = [1,2,3,4,5]
b = [1,1,6,3,8]
m1 = list()
m2 = list()
for x, y in zip(a, b):
m1.append(max(x, y))
for x in itertools.imap(max, a, b):
m2.append(x)
Both of these result in [1, 2, 6, 4, 8], which is correct. Is there a better way?
map(max, a, b)
[max(x, y) for x, y in zip(a, b)]
You could do it like:
a = [1,2,3,4,5]
b = [1,1,6,3,8]
m3 = [max(x,y) for (x,y) in zip(a,b)]
or even
m4 = map(max, zip(a,b))
In Python3, map() no longer returns a list, so you should use the list comprehension or
list(map(max, a, b))
if you really need a list and not just an iterator

Categories