I'm trying to write Matrix Addition function using Python.
Here is the code I've been trying, but it gives me a list index error and I cannot figure out why.
def matrixADD(A,B):
Z = []
#TODO
for i in range(0,len(A)):
for column in range(0, len(A)):
result = A[i][column] + B[i][column]
Z[i][column] = (result)
return Z
using the following lists:
A = [[2,4], [7,0], [6,3]]
B = [[3,1], [-1,8], [-3, 3]]
So in theory, A[0][0] + B[0][0] would equal 5, and I would want to add that value to position Z[0][0].
However I keep receiving the error: IndexError: list index out of range
>>> A = [[2,4], [7,0], [6,3]]
>>> B = [[3,1], [-1,8], [-3, 3]]
>>> Z = [map(sum, zip(*t)) for t in zip(A, B)]
>>> Z
[[5, 5], [6, 8], [3, 6]]
As for how you could fix your current code:
Z = []
for i in range(len(A)):
row = []
for j in range(len(A[i])):
row.append(A[i][j] + B[i][j])
Z.append(row)
The important parts here being that you cannot just assign to Z[i][j] unless that row/column already exists, so you need to construct each inner list separately and append them to Z. Also the inner loop needs to end at the length of a row, so I changed range(len(A)) to range(len(A[i])).
len(A) = 3 but you matrix have dimension 3x2 so when you try to access A[2][2] (because column is between 0 and len(A)) you are out of bounds.
For column you are using range 0 to len(A) (which is 3). A[i][2] will be out of range, because A[i]'s length is only 2.
Try using column range to end a len(A[i]) instead of len(A):
def matrixADD(A,B):
Z = []
#TODO
for i in range(0,len(A)):
for column in range(0, len(A[i])):
result = A[i][column] + B[i][column]
Z[i][j] = (result)
return Z
Related
I have this list of values:
A = [0,0,1,2,3,4,5,6,0,6,6,8,8,0,0,2,3,4,5,12,45,-0,-0,-9,-2,3,-0,-2,-2,-2]
I want to get this list of values for the output :
A = [1,2,3,4,5,6,0,6,6,8,8,2,3,4,5,12,45,-9,-2,3,-0,-2,-2,-2]
Basically, I want to drop the consecutive zeros only, and keep all the other values.
Do you have any idea on how i can do that ? I tried this one but i know there will be in index error :
X = []
for j in range(len(A)):
if A[j] != 0 and A[j+1] != 0:
X.append(A[j])
else:
print('lol')
print(X)```
You can use itertools.groupby and itertools.chain:
from itertools import groupby, chain
out = list(chain.from_iterable(G for k,g in groupby(A)
if len(G:=list(g))<2 or k!=0))
Explanation:
groupby will group the consecutive values. For each group, if the length is no more than 1 or the key (=value) is not 0, keep it. Finally chain all the groups together and convert to list.
Note that groupby returns iterators so I am using an assignment expression to perform the conversion.
output:
[1, 2, 3, 4, 5, 6, 0, 6, 6, 8, 8, 2, 3, 4, 5, 12, 45, -9, -2, 3, 0, -2, -2, -2]
With itertools:
from itertools import groupby
X = [x
for x, [*xs] in groupby(A)
if x or len(xs) == 1
for x in xs]
Alternatively:
X = []
for x, [*xs] in groupby(A):
if x or len(xs) == 1:
X += xs
Or taking any x that's not zero or where the previous and next values are not zero (padding with 1):
X = [x
for p, x, n in zip([1]+A, A, A[1:]+[1])
if x or p and n]
if u dont want to import itertools and prefer list comprehension
A = [i for index,i in enumerate(A) if i!=0 or index not in [0,len(A)] and A[index-1]!=i and A[index+1]!=i ]
note that this expressions uses the precedence of and operator over or operator
enumerate is used too
Here's a more simple, easy, and bit lengthy than other answers method to solve your problem
A = [0,0,1,2,3,4,5,6,0,6,6,8,8,0,0,2,3,4,5,12,45,-0,-0,-9,-2,3,-0,-2,-2,-2]
ind=[i for i,j in enumerate(A) if j==0]
C=[(ind[i],ind[i+1]) for i in range(len(ind)-1) if ind[i]+1==ind[i+1]]
D=[i for i1 in C for i in i1]
E=["" if i in D else j for i,j in enumerate(A)]
F=[i for i in E if i!=""]
# TEST
d_output=[1,2,3,4,5,6,0,6,6,8,8,2,3,4,5,12,45,-9,-2,3,-0,-2,-2,-2]
print(F==d_output)
Output: 1 i.e Your desired output
If you want to specify the value, then you can wrap it up in a function as below:
def remove_c(list_2,val):
ind=[i for i,j in enumerate(list_2) if j==val]
C=[(ind[i],ind[i+1]) for i in range(len(ind)-1) if ind[i]+1==ind[i+1]]
D=[i for i1 in C for i in i1]
E=["" if i in D else j for i,j in enumerate(A)]
return [i for i in E if i!=""]
print(remove_c(A,10))
Explantion:
I have taken all the indexes of 0 in the list.
Checked if the indexes are consecutive or not. If they are, then append them in the list C in tuple.
And, because the list C contains tuple, created a flat list D out of list C.
Replaced the indexes of list D with "".
Removed "" for the list.
I have noticed a silly mistake in your code:
X = []
for j in range(len(A)): # Mistake here
if A[j] != 0 and A[j+1] != 0: # if we bypassed the above error we can also get error here
X.append(A[j])
else:
print('lol')
print(X)
The problem is when the i is at last index of the list, there would be no other index but you have hard-coded to search for index+1, so it would throw an error.
There are 2 method to solve this:
Use try and except.
Replace range(len(A) to range(len(A)-1).
def transpose_matrix(matrix):
n = len(matrix)
vertical_to_horizontal = [[0]*n]*n
for i in range(n):
for j in range(n):
vertical_to_horizontal[i][j] = matrix[j][i]
return vertical_to_horizontal
print(transpose_matrix([[1,2],[3,4]]))
The function is supposed to transpose a n*n matrix, but I get [[2, 4], [2, 4]] instead of the correct answer ([1,3],[2,4]).
I know that there are other ways to transpose a matrix, but my problem is to understand why the code above doesn't give the expected result.
Your algorithm is correct, the problem lies in the way you create your empty matrix at the beginning, with
vertical_to_horizontal = [[0]*n]*n
The inner [0]*n creates a list [0, 0]
Then, the outer * operator creates a list that references twice this inner list - the very same object.
n = 2
v_to_h = [[0]*n] * n
print(id(v_to_h[0]), id(v_to_h[1]))
#140243497120456 140243497120456
The two [0, 0] lists in your matrix are in fact the same object, as their identical ids shows. So, when we do
v_to_h[0][0] = 5
we update the 0th element of v_to_h[0], but v_to_h[0] and v_to_h[1] are the same object, so we get twice the same list in the matrix:
print(v_to_h)
#[[5, 0], [5, 0]]
If you want to prevent that, you have to create different inner lists, so don't use the * operator.
You can use a list comprehension, as in:
n = 2
v_to_h = [[0]*n for i in range(n)]
print(id(v_to_h[0]), id(v_to_h[1]))
#140243437130184 140243512804488
Here, our two lists are different objects.
So, your code could be:
def transpose_matrix(matrix):
n = len(matrix)
vertical_to_horizontal = [[0]*n for i in range(n)]
for i in range(n):
for j in range(n):
vertical_to_horizontal[i][j] = matrix[j][i]
return vertical_to_horizontal
print(transpose_matrix([[1,2],[3,4]]))
#[[1, 3], [2, 4]]
which does what you expect - though there are, of course, shorter and more efficient ways to transpose a matrix, as already indicated in the comments.
def transpose_matrix(matrix):
n = len(matrix)
vertical_to_horizontal = []
for i in range(n):
vertical_to_horizontal.append([i]*n)
for j in range(n):
vertical_to_horizontal[i][j] = matrix[j][i]
return vertical_to_horizontal
print(transpose_matrix([[1,2],[3,4]]))
I am trying to swap the last item with the biggest number in the list but it doesn't print anything
a=[3,4,2,2,43,7]
maxindex=0
for i in range(len(a)):
if a[i] is max(a):
maxno = a[i]
maxindex = i
if a[maxindex] < a[len(a)-1]:
a[maxindex],a[len(a)-1] = a[len(a)-1],a[maxindex]
print(a)
expected result is [3,4,2,2,7,43]
Find indices of the two numbers. Assign them to two separate variables. Then, swap them, like so:
>>> a = [3,4,2,2,43,7]
>>> last_index = a.index(a[-1])
>>> max_num_index = a.index(max(a))
>>> a[last_index], a[max_num_index] = a[max_num_index], a[last_index]
>>> a
[3, 4, 2, 2, 7, 43]
Method 1:
a = [3,43,2,2,43,7]
maximum = max(a)
for index,data in enumerate(a):
if data == maximum:
a[index] = a[-1]
a[-1] = maximum
print a
Method 2[Using list comprehension]:
a = [a[-1] if data == maximum else data for index,data in enumerate(a)]
a[-1] = maximum
print a
you can do this in a simple way: swapping the max item with the last item, by finding the position of the max item
a = [3,4,2,2,43,7]
a[a.index(max(a))], a[-1] = a[-1], a[a.index(max(a))]
print(a)
output:
[3, 4, 2, 2, 7, 43]
To add efficiency (as was pointed out by PM2Ring in the comments), and avoid finding max twice (an O(n) operation), you can first save the index in a variable, and use it in the swap:
a = [3,4,2,2,43,7]
max_index = a.index(max(a))
a[max_index], a[-1] = a[-1], a[max_index]
print(a)
This should solve it:
a=[3,4,2,2,74, 300,70]
a[a.index(max(a))], a[-1] = a[-1], a[a.index(max(a))]
print(a)
Remark: this works only for none duplicated max elements.
So i have a quick question my code is supposed to delete the row and column (from i and j) which it does but for some reason it also changes the original matrix (while i have copied it). Can someone tell me why that is?
def reduce_matrix(M, i, j):
newM=list(M[:])
for q in range(len(newM)+1):
if q==i-1:
del newM[q]
for y in range(len(newM)):
for x in range(len(newM[y])):
if x==j-1:
del newM[y][x]
return newM
You have to copy all sublists in a list, instead of copy all list.
try this:
def reduce_matrix(M, i, j):
newM=[k[:] for k in M]
#rest of code
From your program:. Try to print id of each sublists.
def reduce_matrix(M, i, j):
newM=list(M[:])
print id(M[0]), id(M[1]), id(M[2])
for q in range(len(newM)+1):
if q==i-1:
del newM[q]
for y in range(len(newM)):
for x in range(len(newM[y])):
if x==j-1:
del newM[y][x]
return newM
lis = [[1,2,3],[3,4,5],[7,4,2]]
print id(lis[0]), id(lis[1]), id(lis[2])
reduce_matrix(lis, 1, 1)
>>>
3074546604 3072046316 3072047084
3074546604 3072046316 3072047084
That proves that, sublists are just tagging or pointing to another variable.So modification for any sublist will happen to every sublist with same tags.
For example:
a = [1,2]
b = a
c = a
b.append(3)
print a
print b
print c
>>>
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
Hope this helps.
you only copy the first list, not the sublist.
if you want to return a new matrix with reduce row and column, you can do this:
def reduce_matrix(M, i, j):
return [[M[m][n] for n in range(len(M[m])) if j-1 != n ] \
for m in range(len(M)) if i-1 != m]
I am trying to write a program that sums the integers in the odd columns of a list
def sum_of_odd_cols(x):
for j in range(len(x)):
odds=[x[k][j] for k in range(len(x)) if j%2!=0]
return sum(odds)
x=[[1,2,5],[3,4,6],[7,8,9]]
print(sum_of_odd_cols(x))
What I get from this is '0', why is this happening?
Also one more question
x=[[1,2,5],[3,4,6],[7,8,9]]
for j in range(len(x)):
col=[column[j] for column in x]
this also seems to create a list of the columns in list x, however I don't understand how this works
is 'column' a built in function in python?
How about:
def sum_of_odd_cols(x):
oddsum = 0
for j in range(len(x)):
oddsum += sum([x[k][j] for k in range(len(x)) if j%2!=0])
return oddsum
x=[[1,2,5],[3,4,6],[7,8,9]]
print(sum_of_odd_cols(x))
This probably isn't the best way of doing it, but it will get your code working. The odds variable was getting overwritten by a new list in each iteration of the loop, and since the final column was empty (it's index is even), the sum was always 0.
The reason it returns 0 is because your odds array is empty at the end of the for loop; because in each iteration of the loop you are resetting odds. If you write your loop the 'long' way, it will return the correct results:
odds = []
for j in range(len(x)):
for k in range(len(x)):
if j % 2 != 0:
odds.append(x[k][j])
If I add some print statements, this is what happens:
j is: 0
k is: 0
k is: 1
k is: 2
j is: 1
k is: 0
Adding: 2 to odds
k is: 1
Adding: 4 to odds
k is: 2
Adding: 8 to odds
j is: 2
k is: 0
k is: 1
k is: 2
>>> odds
[2, 4, 8]
For the second part of your question:
Also one more question
x=[[1,2,5],[3,4,6],[7,8,9]] for j in range(len(x)):
col=[column[j] for column in x]
this also seems to create a list of the columns in list x, however I
don't understand how this works is 'column' a built in function in
python?
No, this is a list comprehension, a short-hand way of constructing lists.
The loop is actually:
col = []
for column in x:
col.append(column[j])
Where j is some other variable (set above the comprehension).
If you are comfortable with NumPy:
import numpy as np
a = np.array([[1,2,3], [1,2,3]])
b = np.sum(a[:,::2], axis=0) # column 0, 2, ...
# b = [2, 6]
b = np.sum(a[:,::2])
# b = 8
c = np.sum(a[:,1::2], axis=0) # column 1, 3, ...
You can do
x = [[1,2,5],[3,4,6],[7,8,9]] # Generate the list
sum([sum(k[1::2]) for k in x]) # Sum the numbers in odd columns
# 14
if you need the combined sum for all the numbers in the odd columns.
Your first question has been answered various times.
As for your second question, think about unzipping your nested list (supposing it is not ragged):
>>> x=[[1,2,5],[3,4,6],[7,8,9]]
>>> [x for x in zip(*x)]
[(1, 3, 7), (2, 4, 8), (5, 6, 9)]
This gives you a list containing the columns.
If the tuples are a problem and you need lists inside the list, use the builtin list:
>>> [list(x) for x in zip(*x)]
[[1, 3, 7], [2, 4, 8], [5, 6, 9]]
So basically your two questions boil down to this:
def sum_of_odd_cols(x):
return sum(sum(x[1::2]) for x in x)
def rows_to_columns(x):
return [list(x) for x in zip(*x)]