Double iteration to a list python 3 - python

for x in range(0,img_row):
for y in range(0,img_col):
img_lst.append([img[x,y][0],img[x,y][1],img[x,y][2]])
return img_lst
How do I use list Comprehension here?
img_lst = [img[x,y][0], img[x,y][1], img[x,y][2] y for y in range(0,img_col) for x in range(0, img_row)]
I tried this but it is giving my invalid syntax and when I remove "y" in the beginning it gives me that Y is not defined
the whole function:
def cvimg_to_list(img):
img_row = img.shape[0]
img_col = img.shape[1]
img_lst=[]
img_lst = [img[x,y][0], img[x,y][1], img[x,y][2] y for y in range(0,img_col) for x in range(0, img_row)]
return img_lst

To convert nested loops with a list.append() call to a list comprehension, all you have to do is move everything between the .append(...) parentheses to the front, remove the : colons after the for loops, and finally add [...] around the result:
[
[img[x,y][0],img[x,y][1],img[x,y][2]]
for x in range(0,img_row)
for y in range(0,img_col)
]
Note that the order of the for loops does not change!
This can then be put onto one line; I added some whitespace for readability and simplified the range() calls:
[[img[x, y][0], img[x, y][1], img[x, y][2]]
for x in range(img_row) for y in range(img_col)]
Because you build a new list with the first 3 values from img[x, y], you can also use slicing:
[img[x, y][:3] for x in range(img_row) for y in range(img_col)]
You made three mistakes in your attempt; you swapped the order of the for loops, you added in an extra, stray y, and you dropped the ] closing bracket for the list object you produce each iteration.

I'm not totally sure about what are you trying to achieve, but if my assumption is correct (you want to get a list of pixel values values from the three channels of an image that you opened with opencv), you can use numpy to do this.
img_lst=img.reshape(-1,3).tolist()
Bearing in mind that cv2 loads images as BGR and not RGB.
note: not being properly an answer to the question, I would have rather post this as a comment but I don't have enough reputation for that

Related

Calculation involving iterations over all combinations of values in two lists in Python [duplicate]

This question already has answers here:
How to get the cartesian product of multiple lists
(17 answers)
Closed 5 months ago.
I need to make calculations using two lists each with 36 elements in them. The calculation must use one value in each list using all combinations. Example:
listx = [x1 , x2 , x3 , ... , x36]
listy = [y1 , y2 , y3 , ... , y36]
F(x,y) = ((y-x)*(a/b))+x
x and y in F(x,y) must assume all combinations inside listx and listy. Results should be a matrix of (36 x 36)
This is what I've tried so far:
listx = np.arange(-0.05,0.301,0.01)
listy = np.arange(-0.05,0.301,0.01)
for x in listx:
for y in listy:
F = ((y-x)*(a/b))+x
print(F)
So I think the issue is that you are having trouble conceptualizing the grid that these solutions are supposed to be stored in. This calculation is good because it is an introduction to certain optimizations and additionally there are a few ways to do it. I'll show you the three I threw together.
First, you could do it with lists and loops, which is very inefficient (numpy is just to show the shape):
import numpy as np
x, y = [], []
length = 35
for i in range(length+1):
x.append(i/length) # Normalizing over the range of the grid
y.append(i/length) # to compare to later example
def func(x, y, a, b):
return ((y-x)*(a/b))+x
a=b=1 # Set a value for a and b
row = []
for i in x:
column = []
for j in y:
column.append(func(i,j,a,b))
row.append(column)
print(row)
print(np.shape(row))
This will output a solution assuming a and b are known, and it is a 36x36 matrix. To make the matrix, we have to create a large memory space which I called row and smaller memory spaces that are recreated each iteration of the loop I called column. The inner-most loop appends the values to the column list, while the evaluated column lists are appended to the top level row list. It will then have a matrix-esque appearance even if it is just a list of lists.
A more efficient way to do this is to use numpy. First, we can keep the loops if you wish and do the calculation with numpy arrays:
import numpy as np
x = y = np.linspace(0,1,36)
result = np.zeros((len(x), len(y)))
F = lambda x,y,a,b: ((y-x)*(a/b))+x
a=b=1
for idx, i in enumerate(x):
for jdx, j in enumerate(y):
result[idx, jdx] = F(i,j,a,b) # plug in value at idx, jdx grip point
print(result)
print(result.shape)
So here we create the grid using linspace and I just chose values from 0 to 1 in 36 steps. After this, I create the grid we will store the solutions in by making a numpy array with dimensions given by the length of the x and y arrays. Finally The function is created with a lambda function, which serves the same purpose of the def previously, just in one line. The loop is kept for now, which iterates over the values i, j and indexes of each idx, jdx. The results are added into the allocated storage at each index with result[idx, jdx] = F(i,j,a,b).
We can do better, because numpy exists to help remove loops in calculations. Instead, we can utilize the meshgrid function to create a matrix and evaluate the function with it, as so:
import numpy as np
x = y = np.linspace(0,1,36)
X, Y = np.meshgrid(x,y)
F = lambda x,y,a,b: ((y-x)*(a/b))+x
a=b=1
result = F(X,Y,a,b) # Plug in grid directly
print(result.T)
print(result.shape)
Here we use the numpy arrays and tell meshgrid that we want a 36x36 array with these values at each grid point. Then we define the lambda function as before and pass the new X and Y to the function. The output does not require additional storage or loops, so then we get the result.
It is good to practice using numpy for any calculation you want to do, because they can usually be done without loops.

How to avoid `for` loops for indexing for huge data

This is my code. I would like to avoid for loop for huge number of iterations.
iterations = 10000
max_number = 9700
W = is a matrix(300,9700)
def grad_function(x,y):
grad = np.sum(W*(x - y))
return grad
x = np.arange(300)
y = np.arange(9700)
for i in range (iterations):
for j in range(max_number):
result = grad_function(x,y)
print(result)
I tried using the map() function instead but it does not give me a result including 9700 elements; instead, it gives me a list of 300 elements which is not correct.
I think you're trying to do something like this:
W = np.random.random((300, 9700))
x = np.arange(300)
y = np.arange(9700)
result = (W.T # x) - y
Then result.shape is (9700,). Alternatively, you can make W have shape (9700, 300) and then you won't need to transpose it.
In general, you never need to loop with NumPy. Just do the maths on the arrays directly. The only trick I've used here is # instead of np.matmul.
If you really want to use a function for the maths, be sure to pass in everything it needs:
def grad(x, y, W):
return (W.T # x) - y
As far as I understand a map() does essentially the same as your nested for-loops and if you need to check every value in the matrix, this will be one of the fastest options anyway.

Python matrix indexing

I have the following code
l = len(time) #time is a 300 element list
ll = len(sample) #sample has 3 sublists each with 300 elements
w, h = ll, l
Matrix = [[0 for x in range(w)] for y in range(h)]
for n in range(0,l):
for m in range(0,ll):
x=sample[m]
Matrix[m][n]= x
When I run the code to fill the matrix I get an error message saying "list index out of range" I put in a print statement to see where the error happens and when m=0 and n=3 the matrix goes out of index.
from what I understand on the fourth line of the code I initialize a 3X300 matrix so why does it go out of index at 0X3 ?
You need to change Matrix[m][n]= x to Matrix[n][m]= x
The indexing of nested lists happens from the outside in. So for your code, you'll probably want:
Matrix[n][m] = x
If you prefer the other order, you can build the matrix differently (swap w and h in the list comprehensions).
Note that if you're going to be doing mathematical operations with this matrix, you may want to be using numpy arrays instead of Python lists. They're almost certainly going to be much more efficient at doing math operations than anything you can write yourself in pure Python.
Note that indexing in nested lists in Python happens from outside in, and so you'll have to change the order in which you index into your array, as follows:
Matrix[n][m] = x
For mathematical operations and matrix manipulations, using numpy two-dimensional arrays, is almost always a better choice. You can read more about them here.

Unpacking a tuple in python and iterating over it

I'm trying to unpack a co-ord tuple then iterate over it to blit a sprite multiple times:
def updateMap(self, playerPosition):
self.x_coord, self.y_coord = playerPosition
t = Tree(self.screen)
for x in range(self.x_coord):
for y in range(self.y_coord):
self.screen.fill((0,104,0))
t.drawTree((x, y))
However I get the following error:
File "unnamed.py", line 26, in updateMap
for x, y in range(self.x_coord), range(self.y_coord):
ValueError: need more than 0 values to unpack
Grateful if someone can point me in the right direction on the correct way to do this. Thanks.
EDIT: I have edited my code to the above to iterate over every coord say if playerPostion is 0,5 so the iteration goes (0,1) (0,2) (0,3) (0,4) (0,5) -- but although I'm not getting any errors it seems the tree does not get drawn correctly. Thanks.. it seems to be the answer, except my coding is just wrong.
I think this is what you want instead:
from itertools import product
self.x_coord, self.y_coord = playerPosition #playerPosition is a tuple
t = Tree(self.screen)
for x,y in product(range(self.x_coord+1), range(self.y_coord+1)):
self.screen.fill((0,104,0))
t.drawTree((x, y))
I think the OP wants to iterate over the range of X co-ordinates and the range of Y co-ordinates to create a (x,y) for each case.
for x in range(self.x_coord):
for y in range(self.y_coord):
print(x, y)
Use the built in Python zip function assuming both of the iterables are of the same length. If not then you will need to do a bit of sanitization before to ensure they are.
for x, y in zip(range(self.x_coord), range(self.y_coord))
Maybe if you change:
self.x_coord = 0
self.y_coord = 0
playerPosition = self.x_coord, self.y_coord
to:
self.x_coord, self.y_coord = playerPosition
then you get the player position x and y in to self.x_coord and self.y_coord
And to iterate over every combination of x and y you either need to put a loop over y range inside inside a loop over the x range
for x in range(self.x_coord):
for y in range(self.y_coord):
self.screen.fill((0,104,0))
t.drawTree((x, y))

How to use map lambda of python to make a element to a certain number?

I have a numpy.array called p2De. The first row has multiple elements may larger than 1. I want to set the elements which smaller than 1 to 1. Following is my code, but shows error... why? How to fix it?
bounde=1
p2De[:0]=map(lambda x:bounde if (x < bounde),p2Di[:0])
File "C:\Users\wange\workspace\cathode\src\diffusion.py", line 86
p2De[:0]=map(lambda x:bounde if (x < bounde),p2Di[:0])
^
SyntaxError: invalid syntax
You need to specify an else for your lambda function :
lambda x:bounde if (x < bounde) else #stuff
It should be
lambda x:bounde if (x < bounde) else x
You can also use list comprehension, which is more readable. Also, I would use the max builtin function instead of your lambda:
p2De[:0] = [max(x, bounde) for x in p2Di[:0]]
As others have noted, the syntax problem is in the lambda.
I don't think you want p2De[:0] - that's an empty array. p2De[0] is the 1st row. p2De[0,:] is the same, and makes it clear to the human readers that you have selected the 1st row of a 2d array.
The use of a map or comprehension works, but they don't offer much of an advantage, if any, over a simple loop (since you don't need to replace all of the values):
for i,v in enumerate(p2De[0,:]):
if v<1:
p2De[0,i] = 1
But none of these iterations is good numpy practice. You should try to think in terms of vector operations. A common practice is to use a boolean mask (or indexing) to select the values that should be changed:
I = p2De[0,:]<1 # boolean vector
p2De[0, I] = 1
p2De[0,p2De[0,:]<1]=1 # or one line form
There is also a numpy function that applies limits like this, np.maximum:
p2De[0,:] = np.maximum(p2De[0,:], 1)
np.clip applies both minimum and maximum bounds:
p2De[0,:] = np.clip(p2De[0,:], minbd, maxbd)
np.clip(p2De[0,:], minbd, maxbd, p2De[0,:]) # alt calling method
The Python(3) bosses encourage us to use functions and comprehensions over maps and lambdas. For example if plist was a list like your p2De[0,:] row:
def clip(x):
return 1 if x<1 else x
plist = [clip(x) for x in plist]
plist = [min(x, 1) for x in plist] # using a builtin for this simple case
say if you have a list a, you can do something like this:
a=[2,3,1,7,0,0,8]
bounde=1
b = map(lambda n: n if n > bounde else bounde,a)
print b

Categories

Resources