Iterating through a multidimensional array in Python - python

I have created a multidimensional array in Python like this:
self.cells = np.empty((r,c),dtype=np.object)
Now I want to iterate through all elements of my twodimensional array, and I do not care about the order. How do I achieve this?

It's clear you're using numpy. With numpy you can just do:
for cell in self.cells.flat:
do_somethin(cell)

If you need to change the values of the individual cells then ndenumerate (in numpy) is your friend. Even if you don't it probably still is!
for index,value in ndenumerate( self.cells ):
do_something( value )
self.cells[index] = new_value

Just iterate over one dimension, then the other.
for row in self.cells:
for cell in row:
do_something(cell)
Of course, with only two dimensions, you can compress this down to a single loop using a list comprehension or generator expression, but that's not very scalable or readable:
for cell in (cell for row in self.cells for cell in row):
do_something(cell)
If you need to scale this to multiple dimensions and really want a flat list, you can write a flatten function.

you can get the index of each element as well as the element itself using enumerate command:
for (i,row) in enumerate(cells):
for (j,value) in enumerate(row):
print i,j,value
i,j contain the row and column index of the element and value is the element itself.

How about this:
import itertools
for cell in itertools.chain(*self.cells):
cell.drawCell(surface, posx, posy)

No one has an answer that will work form arbitrarily many dimensions without numpy, so I'll put here a recursive solution that I've used
def iterThrough(lists):
if not hasattr(lists[0], '__iter__'):
for val in lists:
yield val
else:
for l in lists:
for val in iterThrough(l):
yield val
for val in iterThrough(
[[[111,112,113],[121,122,123],[131,132,133]],
[[211,212,213],[221,222,223],[231,232,233]],
[[311,312,313],[321,322,323],[331,332,333]]]):
print(val)
# 111
# 112
# 113
# 121
# ..
This doesn't have very good error checking but it works for me

It may be also worth to mention itertools.product().
cells = [[x*y for y in range(5)] for x in range(10)]
for x,y in itertools.product(range(10), range(5)):
print("(%d, %d) %d" % (x,y,cells[x][y]))
It can create cartesian product of an arbitrary number of iterables:
cells = [[[x*y*z for z in range(3)] for y in range(5)] for x in range(10)]
for x,y,z in itertools.product(range(10), range(5), range(3)):
print("(%d, %d, %d) %d" % (x,y,z,cells[x][y][z]))

Related

Multiply two list of different sizes element wise without using libraries in python

#create a simple list in python
#list comprehension
x = [i for i in range(100)]
print (x)
#using loops
squares = []
for x in range(10):
squares.append(x**2)
print (squares)
multiples = k*[z for z in x] for k in squares
So in the last line of code I am trying to multiply both the lists. the problem is the lists are not of the same side and k*[z for z in x] this part is also incorrect.
For problems with iteration, I suggest anyone to check Loop Like A Native by Ned Batchelder and Looping like a Pro by David Baumgold
Option 1
If you want to multiply them as far as the shortest list goes, zip is your friend:
multiples = [a * b for a, b in zip (x, squares)]
Option 2
If you want a matrix with the product, then you can do it like this
result = [
[a * b for a in x]
for b in squares
]
I don't quite understand what the desired output would be. As the function stands now, you would have a list of lists, where the first element has 100 elements, the second one 400, the third 900, and so on.
One thing that's strange: The expression [z for z in x] defines a list that is identical to x. So, you might just write k*x
If you want to multiply the elements of both lists, you would have to write [[k*z for z in x] for k in squares]. This would lead to a list of 10 lists of 100 elements (or a 10x100-matrix) containing the products of your lists.
If you want to have one list of length 100 in the end that holds some kind of products, you will have to think about how to proceed with the shorter list.
EDIT: Or if you want to multiply them as far as possible until you reach the end of the shorter list, FRANCOIS CYRIL's solution is an elegant way to do so.
You can loop on each array to multiply element by element at the same position in a result array:
i = 0
arrayRes = []
while i < min (len(array1),len(array2)):
arrayRes.append(array1[i]*array2[i])
i+=1
Or do you prefer to multiply them, matrix way?
x = 0
y = 0
arrayRes = []
while x < len(array1):
arrayRes.append([])
while y < len(array2):
arrayRes[x].append(array1[x]*array2[y])
y+=1
x+=1

Performing a row sum and column sum on a list of lists in python

I want to calculate the row sum and column sum of a matrix in python; however, because of infosec requirements I cannot use any external libraries. So to create a matrix, I've used a list of lists, as follows:
matrix = [[0 for x in range(5)] for y in range(5)]
for pos in range(5):
matrix[pos][pos]=1
matrix[2][2]= 0
Now what I want to do is perform a rowsum and a column sum of the matrix. I know how to do a row sum, that's quite easy:
sum(matrix[0])
but what if I wanted to do a column sum? Is there a more elegant and pythonic way to accomplish that beyond brute-forcing it with a for loop, a la
sumval = 0
for pos in range(len(matrix[0])):
sumval = matrix[pos][0] + sumval
which would work, but it isn't pythonic at all.
Can anyone help me out?
colsum = sum(row[0] for row in matrix)
As a note for others who look at this question though, this really is a task best left to numpy. OP is not allowed external libraries however.
I'd suggest:
s = 0
for row in matrix:
s += row[0]
which is the same as you are doing but a bit more readable.
Using something like:
s = sum([row[0] for row in matrix])
is also readable, but slower because you need to do one pass to collect the row[0] elements, and a second to sum.
You can use:
sum([matrix[i][0] for i in range(len(matrix[0]))])
I can suggest, define a method to calculate the sum by rows, which returns the list of sums:
def sum_rows(matrix):
return [sum(row) for row in matrix]
Then define a method that calls sum_rows(matrix) on the transposed matrix:
def sum_cols(matrix):
return sum_rows(map(list, zip(*matrix)))
For transposing a matrix: Transpose list of lists
Alternative to transpose:
def sum_cols_alt(matrix):
return [ sum(row[i] for row in matrix) for i, _ in enumerate(matrix) ]
One way to do this is to use the map function:
for sum_row, sum_col in zip(map(sum, matrix), map(sum, zip(*matrix))):
print(sum_row, sum_col)

Trying to add specific values from a matrix without using numpy

I am supposed to create a function that adds the absolute value of numbers that are larger than a certain number without using any python modules to do it. I wrote this:
def MatrixSumLarge(vals,large):
sum=0
sum1=0
sum2=0
i=0
#looking at the rows of the matrix
for i in range(len(vals[i])):
if abs(vals)>=large:
sum1=sum1+i
#lookinng at the columns of the matrix
for j in range(0,len(vals[j])):
if abs(vals[j])>=large:
sum2=sum2+vals[j]
sum=sum1+sum2
return(sum)
vals=[[1,-2.5,7,4],[-8,9,2,-1.5],[-12,7.5,4.2,11]]
# setting value of large
large = 7.1
#to print the final answer
print('b) Sum of Large Values = ',MatrixSumLarge(vals,large))
And got the error:
TypeError: bad operand type for abs(): 'list'
You vals is a list of list, so vals[i] is a list. However, abs() cannot be applied on a list, it should be applied on a number (floating number, integer, or complex number), see the official document here. You can for example, add an extra loop to add up the element in the row, like sum(abs(x) for x in vals[i] if x >= 2)
You can change 2 to the number you need.
Overall, your function could look something like this
def f(mat, v):
row_sums = [sum(abs(x) for x in row if x >= v) for row in mat]
return sum(row_sums)
From your question, it's not very clear to me whether you wanna
compare abs(x) to v or x to v
sum up abs(x) or x
But you should be able to adjust the code above to suit your need.
There is also a python module that helps you to flatten list of list. The function is called chain.from_iterable. So the above code could also be written like this
from itertools import chain
def f(mat, v):
sums = [sum(abs(x) for x in chain.from_iterable(mat) if x >= v]
return sum(sums)

Surprising behaviour of enumerate function

I wrote some Python code using the enumerate function.
A = [2,3,5,7]
for i, x in enumerate(A):
# calculate product with each element to the right
for j, y in enumerate(A, start=i+1):
print(x*y)
I expected it to calculate 6 products: 2*3, 2*5, 2*7, 3*5, 3*7, 5*7
Instead, it calculated all possible 16 products. What's going on?
The start parameter of enumerate solely influences the first value of the yielded tuple (i.e. i and j), it does not influence at which index the enumeration starts. As the manual puts it, enumerate is equivalent to this:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
What you want is this:
for i, x in enumerate(A):
for y in A[i + 1:]:
print(x * y)
The question here is firstly what enumerate did, and secondly why you're using it. The base function of enumerate is to convert an iterable of the form (a,b,c) to an iterable of the form ((start,a), (start+1,b), (start+2,c)). It adds a new column which is typically used as an index; in your code, this is i and j. It doesn't change the entries contained in the sequence.
I believe the operation you were intending is a slice, extracting only part of the list:
for i, x in enumerate(A):
for y in A[i+1:]:
print(x*y)
If it is important not to copy the list (it rarely is), you can replace A[i+1:] with itertools.islice(A, i+1, len(A)).
A side note is that the start argument may be useful in the outer loop in this code. We're only using i+1, not i so we may as well use that value as our index:
for nextindex, x in enumerate(A, 1):
for y in A[nextindex:]:
print(x*y)

Obtaining the first and second "column's" from a pair of lists

I have many pairs of lists of variable lengths (5,4,6 pairs etc..) inside a single big list, lets call it LIST. Here are two lists among the many inside the big LIST as an example:
[(38.621833, -10.825707),
(38.572191, -10.84311), -----> LIST[0]
(38.580202, -10.860877),
(38.610917, -10.85217),
(38.631526, -10.839338)]
[(38.28152, -10.744559),
(38.246368, -10.744552), -----> LIST[1]
(38.246358, -10.779088),
(38.281515, -10.779096)]
I need to create two seperate variables lets say, of which one variable will have the first "column" (i.e. LIST[0][0][0], LIST[0][1][0] AND SO ON) of all the pairs of the lists(i.e. 38.621833, 38.572191 etc) and the second variable will have the second "column" (i.e. LIST[0][0][1], LIST[0][1][1] AND SO ON) of all the pairs of the lists.
So finally I will have two variables (say x,y) that will contain all the values of the first and second "columns" of all the lists in the LIST.
The problem I face is that all these lists are not of the same length!!
I tried
x = []
y = []
for i in range(len(LIST)):
x.append(LIST[i][0][0]) #append all the values of the first numbers
y.append(LIST[i][1][1]) #append all the values of the second numbers
What I expect:
x = (38.621833,38.572191,38.580202,38.610917,38.631526,38.28152,38.246368,38.246358,38.281515)
y = (-10.825707,-10.84311,-10.860877,-10.85217,-10.839338,-10.744559,-10.744552,-10.779088,-10.779096)
But here because of the variable pairs, my loop stops abrubptly in between.
I know I need to also change the LIST[i][j][0] here, and j changes with each list. But because of the different pairs, I don't know how to go about.
How do I go about doing this?
I would use two simple for loops (it's also generic for LIST being longer than 2):
x=[]
y=[]
for i in range(len(LIST)):
for j in LIST[i]:
x.append(j[0])
y.append(j[1])
You should transpose the sublists and use itertool.chain to create a single list:
from itertools import chain
zipped = [zip(*x) for x in l]
x, y = chain.from_iterable(ele[0] for ele in zipped),chain.from_iterable(ele[1] for ele in zipped)
print(list(x),list(y))
[38.621833, 38.572191, 38.580202, 38.610917, 38.631526, 38.28152, 38.246368, 38.246358, 38.281515] [-10.825707, -10.84311, -10.860877, -10.85217, -10.839338, -10.744559, -10.744552, -10.779088, -10.779096]
for ele1,ele2 in zip(x,y):
print(ele1,ele2)
38.621833 -10.825707
38.572191 -10.84311
38.580202 -10.860877
38.610917 -10.85217
38.631526 -10.839338
38.28152 -10.744559
38.246368 -10.744552
38.246358 -10.779088
38.281515 -10.779096
Here you go. tuple as requested.
my = [(38.621833, -10.825707),(38.572191, -10.84311),(38.580202, -10.860877),(38.610917, -10.85217),(38.631526, -10.839338)]
my1 = [(38.28152, -10.744559),(38.246368, -10.744552),(38.246358, -10.779088),(38.281515, -10.779096)]
l1 = map(tuple,zip(*my))[0]
l2 = map(tuple,zip(*my))[1]
print l1,l2
Output:
(38.621833, 38.572191, 38.580202, 38.610917, 38.631526)(-10.825707, -10.84311, -10.860877, -10.85217, -10.839338)
Use map function with zip and * stuple operator.
l = [(38.621833, -10.825707),
(38.572191, -10.84311),
(38.580202, -10.860877),
(38.610917, -10.85217),
(38.631526, -10.839338)]
x= map(list, zip(*l))[0]
y = map(list, zip(*l))[1]
print 'x = {},\n y = {}' .format(x,y)
x = [38.621833, 38.572191, 38.580202, 38.610917, 38.631526],
y = [-10.825707, -10.84311, -10.860877, -10.85217, -10.839338]
or if you don't want to store it in variables then d0n't use indexing in above solution,
map(list, zip(*l)) # will give you a nested list
Your LIST extends out of 2 lists.
With
for i in range(len(LIST)):
you run exactly 2 times through your loop.
If you want to solve your problem with for-loops your need to nest them:
#declare x, y as lists
x = []
y = []
for i_list in LIST:
#outer for-loop runs 2 times - one for each list appended to LIST.
#1st run: i_list becomes LIST[0]
#2nd run: i_list becomes LIST[1]
for touple in i_list:
#inner for-loop runs as often as the number of tuple appended to i_list
#touple becomes the content of i_list[#run]
x.append(touple[0]) #adds x-value to x
y.append(touple[1]) #adds y-value to y
If you prefer working with indexes use:
for i in range(len(LIST)):
for j in range(len(LIST[i])):
x.append(LIST[i][j][0])
y.append(LIST[i][j][1]])
NOT working with indexes for appending x- or y-values is much easier to write (saves complex thoughts about the List-Structure and correct using of indexes) and is much more comprehensible for extern people reading your code.

Categories

Resources