Given two matrices, print the product of those matrices - python

I have to check if the given matrices can be multiplied, and if yes, return the product.
I cannot use numpy to calculate the product.
Example used:
A = [[1,2],[3,4]]
B = [[1,2,3,4,5],[5,6,7,8,9]]
Expected output: A*B = [[11,14,17,20,23],[23,30,37, 44,51]]
Here's my code and output:
def matrix_mult(A,B):
countA = 0
countB = 0
result = [[0]*len(B[0])]*len(A)
for i in range(len(A)):
if A[i][1]:
countA += 1
for i in range(len(B)):
if B:
countB += 1
if countA == countB:
for i in range(len(A)):
for j in range(len(B[0])):
for k in range(len(A)):
result[i][j] += A[i][k]*B[k][j]
return result
A = [[1,2],[3,4]]
B = [[1,2,3,4,5], [5,6,7,8,9]]
matrix_mult(A,B)
output:
[[34, 44, 54, 64, 74], [34, 44, 54, 64, 74]]
Is there something wrong with the code/logic?

The guilty is your result declaration. It's not a good way to declare a list by duplicating the elements (not creating a proper matrix). More details in this discussion.
Try:
result = [[0 for _ in range(len(B[0]))] for _ in range(len(A))]
Instead of:
result = [[0] * len(B[0]) ] * len(A)
And that should work fine !

Why make the code so long? You can try this -
def dot(A, B):
return [[sum(x*y for x, y in zip(A_row, B_column)) for B_column in zip(*B)] for A_row in A]
A = [[1,2],[3,4]]
B = [[1,2,3,4,5],[5,6,7,8,9]]
result = dot(A, B)
print(result)
#[[11, 14, 17, 20, 23], [23, 30, 37, 44, 51]]
See if this helps you.

I will recommend using numpy:
import numpy as np
A = np.array([[1,2],[3,4]])
B = np.array([[1,2,3,4,5],[5,6,7,8,9]])
np.matmul(A, B)
# output : array([[11, 14, 17, 20, 23],
# [23, 30, 37, 44, 51]])
with your code there are several issues, below I was trying to improve your code:
def matrix_mult(A,B):
num_col_a = len(A[0])
num_rows_b = len(B)
result = [[0 for _ in range(len(B[0]))] for _ in range(len(A))]
if num_col_a == num_rows_b:
for row_a_index, row_a in enumerate(A):
for col_index, col_b in enumerate(zip(*B)):
result[row_a_index][col_index] = sum(a * b for a, b in zip(row_a, col_b))
return result
A = [[1,2],[3,4]]
B = [[1,2,3,4,5], [5,6,7,8,9]]
print(matrix_mult(A,B))
# output: [[11, 14, 17, 20, 23], [23, 30, 37, 44, 51]]

Related

Loop of List into a Tabbed New List

I am a high school student. By observing the inputted sequence, I want to create a program that creates general formulas on quadratic to a polynomial with nth power equations. This posted code will function as a means of validation for inputted sequences. If you have a better code, please help me. Thank You!
The same concept was shown below,
here is my code
def shrink(numbers):
n1 = [(x, numbers[i+1]) for i, x in enumerate(numbers)
if i < len(numbers)-1]
n2 = [x[1]-x[0] for x in n1]
print(n2)
if(len(n2) > 1):
return shrink(n2)
return n
#shrink([1, 8, 27, 64, 125, 216])
a = input()
b = a.split()
for i in range(len(b)):
b[i] = int(b[i])
shrink(b)
"""
The output will be:
[7, 19, 37, 61, 91]
[12, 18, 24, 30]
[6, 6, 6]
[0, 0]
[0]
"""
#I want the output from the top to be like this!
d = [
[7, 19, 37, 61, 91],
[12, 18, 24, 30],
[6, 6, 6],
[0, 0],
[0]
]
if d[2][0] == d[2][1]:
print('cubic sequence')
During the first call you initialize a list variable which you update and pass to the recursive call
def shrink(numbers,return_list = []):
n1 = [(x, numbers[i+1]) for i, x in enumerate(numbers) if i < len(numbers)-1]
n2 = [x[1]-x[0] for x in n1]
return_list.append(n2)
if(len(n2) > 1):
return shrink(n2,return_list)
else:
return return_list
print(shrink([1, 8, 27, 64, 125, 216]))
If you want the values of n1 as well :
def shrink(numbers,n1_list = [], n2_list = []):
n1 = [(x, numbers[i+1]) for i, x in enumerate(numbers) if i < len(numbers)-1]
n2 = [x[1]-x[0] for x in n1]
n1_list.append(n1)
n2_list.append(n2)
# print(n2)
if(len(n2) > 1):
return shrink(n2,n1_list,n2_list)
else:
return n1_list,n2_list
print(shrink([1, 8, 27, 64, 125, 216]))
Thank You Atharva Gundawar.
If you want the list to be inputted, this is the answer:
Take note that input list should be separated by space and not by a comma.
Sample input: 1 8 27 64 125 216
def shrink(numbers, return_list=[]):
n1 = [(x, numbers[i + 1]) for i, x in enumerate(numbers) if i < len(numbers) - 1]
n2 = [x[1] - x[0] for x in n1]
return_list.append(n2)
if (len(n2) > 1):
return shrink(n2, return_list)
else:
return return_list
a = input()
b = a.split()
for i in range(len(b)):
b[i] = int(b[i])
c = shrink(b)
print(shrink(b))
print(c[2][0])
print(c[2][1])
if c[2][0] == c[2][1]:
print('cubic sequence')
Input:
1 8 27 64 125 216
Output:
[[7, 19, 37, 61, 91], [12, 18, 24, 30], [6, 6, 6], [0, 0], [0], [7, 19, 37, 61, 91], [12, 18, 24, 30], [6, 6, 6], [0, 0], [0]]
6
6
cubic sequence
This is the correct answer to eradicate the loop:
https://stackoverflow.com/posts/70423499/revisions
def shrink(numbers, return_list=[]):
n1 = [(x, numbers[i + 1]) for i, x in enumerate(numbers) if i < len(numbers) - 1]
n2 = [x[1] - x[0] for x in n1]
return_list.append(n2)
if (len(n2) > 1):
return shrink(n2, return_list)
else:
return return_list
input_user = input("Enter data:")
b = input_user.split()
for num in range(len(b)):
b[num] = int(b[num])
c = shrink(b)
print(c)

List comprehension over 2 independent lists

I have two lists like:
a = [10, 35, 57, 79]
b = [13, 41, 65, 80]
I want to get list with pairs of a number and value, where value is True for elements from the list a.
I can do it with;
a_list = [(item, True) for item in a]
b_list = [(item, False) for item in b]
result = a_list + b_list
Is it possible to union these two list comprehensions and make the code simpler?
I can suggest:
list(zip(a + b, [True] * len(a) + [False] * len(b)))
you can use this:
[y for x in [list1, list2] for y in x]
a = [10, 35, 57, 79]
b = [13, 41, 65, 80]
result = [y for x in [[(item, True) for item in a], [(item, False) for item in b]] for y in x]

Find elements in list with difference of 1

Suppose I have a list like this:
lst = [1, 3, 4, 5, 8, 10, 14, 20, 21, 22, 23, 40, 47, 48]
I need to extract the elements which have a difference of one. I need final output to look like this:
[[3, 4, 5], [20, 21, 22, 23], [47, 48]]
Here is what I have tried so far for this particular problem which has yielded some progress but doesn't achieve 100% of what I need:
final_list = []
for i in range(len(lst)):
sub_list = []
for ii in range(i, len(lst)):
prev_num = lst[ii-1]
if lst[ii] - prev_num == 1:
# print(lst[ii], end=",")
sub_array.append(lst[ii])
else:
break
if sub_list:
final_list.append(sub_list)
print(final_list)
Output:
[[4, 5], [5], [21, 22, 23], [22, 23], [23], [48]]
You can use itertools.groupby to group the items with a key function that subtracts each item value with an incremental counter, which would result in a fixed value for each group of consecutive integers:
from itertools import groupby, count
lst = [1, 3, 4, 5, 8, 10, 14, 20, 21, 22, 23, 40, 47, 48]
c = count()
final_list = [g for _, [*g] in groupby(lst, lambda t: t - next(c)) if len(g) > 1]
final_list would become:
[[3, 4, 5], [20, 21, 22, 23], [47, 48]]
EDIT: If you'd rather have better performance than more concise code, you can look at #MadPhysicist's answer, which avoids overhead incurred from calling generator functions, and #don'ttalkjustcode's answer, which avoids creating lists until a pair of consecutive numbers are found. Combine the two answers and you get a solution that avoids both types of overhead:
out = []
prev = float('inf')
for i in lst:
if i - prev != 1:
current = None
elif current:
current.append(i)
else:
current = [prev, i]
out.append(current)
prev = i
Sample timing using #don'ttalkjustcode's benchmark code:
2716 μs Mad_Physicist
1554 μs dont_talk_just_code
1284 μs Mad_Physicist_x_dont_talk_just_code
Try it online!
You can step along the input list and start adding elements to an output list. Any time the difference is greater than 1, start a new output list. If the prior output is length 1, remove it:
out = []
current = []
prev = None
for i in lst:
if prev is None or i - prev != 1:
if len(current) > 1:
out.append(current)
current = []
current.append(i)
prev = i
if len(current) > 1:
out.append(current)
A zip solution that adds each first pair of a streak as an inner list and then appends further elements of the streak:
out = []
inner = None
for x, y in zip(lst, lst[1:]):
if y - x == 1:
if inner:
inner.append(y)
else:
inner = [x, y]
out.append(inner)
else:
inner = None
Benchmark with a random list 1000 as long as your example and with same density:
5172 μs blhsing
2697 μs Mad_Physicist
7667 μs Osman_Mamun
1571 μs dont_talk_just_code
Benchmark code (Try it online!):
from timeit import timeit
from itertools import groupby, count
from random import sample
def blhsing(lst):
c = count()
return [g for _, [*g] in groupby(lst, lambda t: t - next(c)) if len(g) > 1]
def Mad_Physicist(lst):
out = []
current = []
prev = None
for i in lst:
if prev is None or i - prev > 1:
if len(current) > 1:
out.append(current)
current = []
current.append(i)
prev = i
if len(current) > 1:
out.append(current)
return out
def Osman_Mamun(lst):
out = []
for k, g in groupby(enumerate(lst), key=lambda i: i[1]-i[0]):
temp = list(g)
if len(temp) > 1:
out.append([i[1] for i in temp])
return out
def dont_talk_just_code(lst):
out = []
inner = None
for x, y in zip(lst, lst[1:]):
if y - x == 1:
if inner:
inner.append(y)
else:
inner = [x, y]
out.append(inner)
else:
inner = None
return out
lst_example = [1, 3, 4, 5, 8, 10, 14, 20, 21, 22, 23, 40, 47, 48]
funcs = blhsing, Mad_Physicist, Osman_Mamun, dont_talk_just_code
for _ in range(3):
lst = sorted(sample(range(max(lst_example) * 1000), len(lst_example) * 1000))
# lst = lst_example
results = []
for func in funcs:
t = timeit(lambda: results.append(func(lst)), number=100) / 100
print('%d μs ' % (t * 1e6), func.__name__)
assert all(result == results[0] for result in results), (list(map(len, results)), results)
print()
Using itertools.groupby:
In [19]: out = []
In [20]: for k, g in groupby(enumerate(lst), key=lambda i: i[1]-i[0]):
...: temp = list(g)
...: if len(temp) > 1:
...: out.append([i[1] for i in temp])
...:
In [21]: out
Out[21]: [[3, 4, 5], [20, 21, 22, 23], [47, 48]]
You can go through the elements and either add them as a new group or add them to the last group depending on whether it is one more than the last one added. When done, remove the single element groups.
lst = [1, 3, 4, 5, 8, 10, 14, 20, 21, 22, 23, 40, 47, 48]
groups = []
for n in lst:
if groups and n-1 == groups[-1][-1]:
groups[-1].append(n) # +1 element, add to last group
else:
groups.append([n]) # add as a new group
groups = [g for g in groups if len(g)>1] # remove single element groups
print(groups)
[[3, 4, 5], [20, 21, 22, 23], [47, 48]]

How to create an NumPy array based on the index stored in another array?

Let say I have this NumPY array
A =
array([[0, 1, 3],
[1, 2, 4]])
I have another array
B =
array([[10, 41, 26, 50, 12, 24],
[20, 15, 42, 40, 41, 62]])
I wanted to create another array, where it selects the element in B using the index of the column in A. That is
C =
array([[10, 41, 50],
[15, 42, 41]])
Try:
B[[[0],[1]], A]
Or more generally:
B[np.arange(A.shape[0])[:,None], A]
Output:
array([[10, 41, 50],
[15, 42, 41]])
You can use np.take_along_axis
np.take_along_axis(B, A, axis=1)
output:
array([[10, 41, 50],
[15, 42, 41]])
This can be simply done using list rather than numpy
Though, in the ending we can convert it into numpy.
Code:
import numpy as np
#to make it simpler take a 1d list
a = [0,1,3]
b = [10, 41, 26, 50, 12, 24]
c = []
a = np.array(a)
b = np.array(b)
#here we are using for loop to find the value in a and append the index of b in c
for i in range(len(a)):
print(i)
i = a[i]
c.append(b[i])
print(c)
c = np.array(c)
print(type(c))
#To make it more fun, you can use the random module to get random digits

Python: How to efficiently count the number of "1"s in the binary representation of 1 to n numbers?

E.g. For the input 5, the output should be 7.
(bin(1) = 1, bin(2) = 10 ... bin(5) = 101) --> 1 + 1 + 2 + 1 + 2 = 7
Here's what I've tried, but it isn't a very efficient algorithm, considering that I iterate the loop once for each integer. My code (Python 3):
i = int(input())
a = 0
for b in range(i+1):
a = a + bin(b).count("1")
print(a)
Thank you!
Here's a solution based on the recurrence relation from OEIS:
def onecount(n):
if n == 0:
return 0
if n % 2 == 0:
m = n/2
return onecount(m) + onecount(m-1) + m
m = (n-1)/2
return 2*onecount(m)+m+1
>>> [onecount(i) for i in range(30)]
[0, 1, 2, 4, 5, 7, 9, 12, 13, 15, 17, 20, 22, 25, 28, 32, 33, 35, 37, 40, 42, 45, 48, 52, 54, 57, 60, 64, 67, 71]
gmpy2, due to Alex Martella et al, seems to perform better, at least on my Win10 machine.
from time import time
import gmpy2
def onecount(n):
if n == 0:
return 0
if n % 2 == 0:
m = n/2
return onecount(m) + onecount(m-1) + m
m = (n-1)/2
return 2*onecount(m)+m+1
N = 10000
initial = time()
for _ in range(N):
for i in range(30):
onecount(i)
print (time()-initial)
initial = time()
for _ in range(N):
total = 0
for i in range(30):
total+=gmpy2.popcount(i)
print (time()-initial)
Here's the output:
1.7816979885101318
0.07404899597167969
If you want a list, and you're using >Py3.2:
>>> from itertools import accumulate
>>> result = list(accumulate([gmpy2.popcount(_) for _ in range(30)]))
>>> result
[0, 1, 2, 4, 5, 7, 9, 12, 13, 15, 17, 20, 22, 25, 28, 32, 33, 35, 37, 40, 42, 45, 48, 52, 54, 57, 60, 64, 67, 71]

Categories