I have a certain function that I made and I want to run it on each column and each row of a matrix, to check if there are rows and columns that produce the same output.
for example:
matrix = [[1,2,3],
[7,8,9]]
I want to run the function, lets call it myfun
, on each column [1,7]
, [2,8]
and [3,9]
separatly, and also run it on each row [1,2,3]
and [7,8,9]
. If there is a row and a column that produce the same result, the counter ct
would go up 1. All of this is found in another function, called count_good
, which basically counts rows and columns that produce the same result.
here is the code so far:
def count_good(mat):
ct = 0
for i in mat:
for j in mat:
if myfun(i) == myfun(j):
ct = 1
return ct
However, when I use print to check my code I get this:
mat = [[1,2,3],[7,8,9]]
for i in mat:
for j in mat:
print(i,j)
[1, 2, 3] [1, 2, 3]
[1, 2, 3] [7, 8, 9]
[7, 8, 9] [1, 2, 3]
[7, 8, 9] [7, 8, 9]
I see that the code does not return what I need' which means that the count_good
function won't work. How can I run a function on each row and each column? I need to do it without any help of outside libraries, no map
,zip
or stuff like that, only very pure python.
CodePudding user response:
Let's start by using itertools
and collections
for this, then translate it back to "pure" python.
from itertools import product, starmap, chain # combinations?
from collections import Counter
To iterate in a nested loop efficiently, you can use itertools.product
. You can use starmap
to expand the arguments of a function as well. Here is a generator of the values of myfun
over the rows:
starmap(myfun, product(matrix, repeat=2))
To transpose the matrix and iterate over the columns, use the zip(*
idiom:
starmap(myfun, product(zip(*matrix), repeat=2))
You can use collections.Counter
to map all the repeats for each possible return value:
Counter(starmap(myfun, chain(product(matrix, repeat=2), product(zip(*matrix), repeat=2))))
If you want to avoid running myfun
on the same elements, replace product(..., repeat=2)
with combinations(..., 2)
.
Now that you have the layout of how to do this, replace all the external library stuff with equivalent builtins:
counter = {}
for i in range(len(matrix)):
for j in range(len(matrix)):
result = myfun(matrix[i], matrix[j])
counter[result] = counter.get(result, 0) 1
for i in range(len(matrix[0])):
for j in range(len(matrix[0])):
c1 = [matrix[row][i] for row in range(len(matrix))]
c2 = [matrix[row][j] for row in range(len(matrix))]
result = myfun(c1, c2)
counter[result] = counter.get(result, 0) 1
If you want combinations instead, replace the loop pairs with
for i in range(len(...) - 1):
for j in range(i 1, len(...)):
CodePudding user response:
Using native python:
def count_good(mat):
ct = 0
for row in mat:
for col_idx in range(len(mat[0])):
column = [x[col_idx] for x in mat]
if myfun(row) == myfun(column):
ct = 1
return ct
However, this is very inefficient as it is a triple nested for-loop. I would suggest using numpy instead.
e.g.
def count_good(mat):
ct = 0
mat = np.array(mat)
for row in mat:
for column in mat.T:
if myfun(row) == myfun(column):
ct = 1
return ct