Unpacking a tuple in python and iterating over it - python

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))

Related

Select a random element from a 2d array list in python

I currently have a 2d array generated by this code:
for y in range(width):
self.grid.append([])
for x in range(width):
self.grid[y].append(Cell(x, y))
If I want to select a random cell, how would I go about it? random.choice doesn't seem to be working.
You could do something like
yCoord = random.randrange(width)
xCoord = random.randrange(width)
randomCell = self.grid[yCoord][xCoord]
If you do want to use random.choice, you'll have to use it twice, as the first call will return an array of Cells, then the second one will return a cell element.
You can use:
s = list[random.randint(0, len(list) - 1]
rn = s[random.randint(0, len(s) - 1]
You need to use double lines as you need to find the length of the sublist. I don't know or think any direct way exists.

Let Python find two integers satisfying condition

Set-up
I'm looking for all the integer pairs (x,y) in 2 closed sets: [822,2000] and [506,1231] such that x/y=1.624.
Code so far
I tried,
a = [[(x,y)] for x in range(822,2001) and y in range(506,1232) if x/y = 1.624]
But this gives a SyntaxError: invalid syntax pointing to the = in the code.
And if I do,
a = [[(x,y)] for x in range(822,2001) and y in range(506,1232) if x/y <= 1.624]
I get NameError: name 'y' is not defined.
How do I solve this?
Comparing float calculations with == is difficult due to the nature of float arithmetics.
It is often better to compare like this:
a = [(x,y) for x in range(822,2001) for y in range(506,1232) if abs(x/y - 1.624) < 0.00001]
print(set(a))
By substracting the wanted value from your result and and comparing its absolute value against something kindof small you get better results.
Result (using a set):
{(1624, 1000), (1637, 1008), (1015, 625), (1611, 992), (1840, 1133),
(1814, 1117), (1827, 1125), (1408, 867), (1218, 750), (1434, 883),
(1421, 875)}
Python rounding error with float numbers
For the first one you are using the assignment operator instead of the equivalent operator so it should be:
a = [[(x,y)] for x in range(822,2001) and y in range(506,1232) if x/y == 1.624]
And for the second you're probably better off using two for loops
a = [[(x,y)] for x in range(822,2001) for y in range(506,1232) if x/y <= 1.624]
The second one would not make sense as you said it because x and y are coming from lists that have an unequal number of elements so you cannot loop over them like that

Double iteration to a list python 3

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

Counting Values That Are Between an X and Y Coordinate

I have a whole set of data. This data is in x and y coordinates. I'm trying to write a program that counts the amount of data between x and y coordinates...
So for example, let's say I have
(3,4)
(6,3)
(7,6)
(5,5)
(6,7)
and I can only count the data where 5<x<7 and 4<y<6
Then, the coords this program would count is:
(5,5)
(7,6)
So I would get 2.
I can figure out how to do this if I only set one constraint... For example if I just had a list of 1,2,3,4,5,6,7,8 and needed to count the numbers where 3<x<7... I could do that. However, I'm having trouble figuring out how to handle this if there's two constraints.
Thank you so much!
You can use an and to state that both conditions should be satisfied. For example:
sum(5<=x<=7 and 4<=y<=6 for x,y in coord_list)
with coord_list the list of coordinates. Note that in order to satisfy the fact that the count should be 2, you should use less than or equal (<=) operators instead of less than operators (<).
This produces:
>>> coord_list = [(3,4),(6,3),(7,6),(5,5),(6,7)]
>>> sum(5<=x<=7 and 4<=y<=6 for x,y in coord_list)
2
You can obtain the list of coordinates, for instance using list comprehension:
[(x,y) for x,y in coord_list if 5<=x<=7 and 4<=y<=6]
If the number of elements in a point is arbitrary, it is better to use indexing:
[t for t in coord_list if 5<=t[0]<=7 and 4<=t[1]<=6]

Basic Python programming help needed: Arrays and random locations

Consider a 100X100 array.
i) Generate an array of several thousand random locations within such an array, e.g. (3,75) and (56, 34).
ii) Calculate how often one of your random locations falls within 15 pixels of any of the (straight) edges.
I am trying to do the above question in order to help me to learn the programming language Python, i am new to programming.
Here is what i have got so far:
from __future__ import division
from pylab import *
import math as m
from numpy import *
from random import randrange
N = 3000
coords_array = array([randrange(100) for _ in range(2 * N)]).reshape(N, 2)
This creates the array of N random locations, and no i am trying to create a loop that will append a 1 to an empty list if x>85 or y>85 or x<15 or y<15, then append a zero to the same empty list if x or y is anything else. Then i would find the sum of the list, which would be my count of how many of the random location fall within the edges.
This is the kind of thing i am trying to do:
coordinate=coords_array[x,y]
b=[]
def location(x,y):
if x>85 or y>85:
b.appnend(1)
if x<15 or y<15:
b.append(1)
else:
b.append(0)
print b
print x
But i am having trouble assigning the array as x and y variables. I want to be able assign each row of the set of random coordinates as an x,y pair so that i can use it in my loop.
But i do not know how to do it!
Please can someone show me how to do it?
Thank you
Ok, the answer to this:
But i am having trouble assigning the array as x and y variables. I
want to be able assign each row of the set of random coordinates as an
x,y pair so that i can use it in my loop
Would be this:
for pair in coords_array:
# Do something with the pair
NumPy arrays behave as regular Python sequences by letting for to iterate over their main axis, meaning pair will contain an array of (in your case) two elements: x and y. You can also do this:
for x, y in coords_array:
# Do something with the pair
NB: I think you wanted to write the function like this:
def location(x,y):
if x>85 or y>85:
b.append(1)
elif x<15 or y<15:
b.append(1)
else:
b.append(0)
or
def location(x,y):
if x>85 or y>85 or x<15 or y<15:
b.append(1)
else:
b.append(0)
or even
def location(x,y):
if not (15 <= x <= 85) or not (15 <= y <= 85):
b.append(1)
else:
b.append(0)
Otherwise, as #TokenMacGuy points out, you'd be inserting two values in certain cases.
NB: from your question I understand you want to write this code specifically to learn Python, but you could do this in a much more straightforward (and efficient) way by just using NumPy functionality
You can let numpy do the looping for you:
n = 3000
coords = np.random.randint(100, size=(n, 2))
x, y = coords.T
is_close_to_edge = (x < 15) | (x >= 85) | (y < 15) | (y >= 85)
count_close_to_edge = np.sum(is_close_to_edge)
Note that the first index of a 100 element array is 0 and the last 99, hence items within 15 positions of the edges are 0...14 and 85...99, hence the >= in the comparison. In the code above, is_close_to_edge is your list, with boolean values.

Categories

Resources