Finding adjacent cells in a grid without exceptions - python

There are times when I have an area in a 2D array, and I need to check for adjacent cells. Normally I would do the following:
adjacentCells = (world[y+1][x]==1)+(world[y-1]==1)+(world[y][x+1]==1)+(world[y][x-1]==1)
This would calculate how many orthogonally adjacent cells to the point (x,y) are equal to 1. The issue is, doing things this way wraps around the matrix if my x or y coordinates are 0 (the top or left edge), and it causes an exception if the point (x,y) is on a different edge. This makes the code look like this:
def adjacentCells(x,y):
total=0
if x==0:
total += 1
else:
total += world[y][x-1]
if y==0:
total += 1
else:
total += world[y-1][x]
try:
total += world[y][x+1]
except:
total += 1
try:
total += world[y+1][x]
except:
total += 1
return total
Is there a way to fix this issue, in a way about as simple as the uppermost example?

I would do it something like this:
def adjacentCells(x, y):
neighbours = [(x-1, y), (x, y-1), (x+1, y), (x, y+1)]
return sum(
world[b][a] if 0 <= b < len(world) and 0 <= a < len(world[b])
else 1
for (a,b) in neighbours)
So get a list of potential neighbours but check each one is valid before you use it.
If the neighbours of border cells counted as 0 instead of 1 it would be simpler, then you would simply filter the list of neighbours before using it.

For doing something as trivial as adding up the values of up to 4 cells, I'd just write the code for each case—it only requires one line per cell location. It may be longer than using a loop construct, but avoids looping overhead and it's all pretty much boilerplate.
It's also relatively easy to read and understand, and would make it easier to special-case one of the locations should doing that be needed for some reason.
Here's what I mean:
world = [[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]
MIN_X, MAX_X = 0, len(world[0])-1
MIN_Y, MAX_Y = 0, len(world)-1
def adjacentCells(x, y):
return((world[ y][x-1] if MIN_Y <= y <= MAX_Y and MIN_X <= x-1 <= MAX_X else 1)
+ (world[ y][x+1] if MIN_Y <= y <= MAX_Y and MIN_X <= x+1 <= MAX_X else 1)
+ (world[y-1][ x] if MIN_Y <= y-1 <= MAX_Y and MIN_X <= x <= MAX_X else 1)
+ (world[y+1][ x] if MIN_Y <= y+1 <= MAX_Y and MIN_X <= x <= MAX_X else 1))
print(adjacentCells(0, 0)) # -> 4
print(adjacentCells(1, 1)) # -> 4

Related

How to save the minimum path sum in a recursive function?

This is my solution to given a matrix m x n, find the minimum path sum. It works fine however, I'm not sure how to modify it to see the path / save it in some list, how can this be done?
def get_path(matrix, x, y, seen):
if (x, y) in seen:
return seen[x, y]
x_end = len(matrix) - 1
y_end = len(matrix[0]) - 1
current = matrix[x][y]
if x == x_end and y == y_end:
return current
possible_moves = []
if x < len(matrix) - 1:
possible_moves.append([x + 1, y])
if y < len(matrix[0]) - 1:
possible_moves.append([x, y + 1])
results = [
current + get_path(matrix, *possible, seen) for possible in possible_moves
]
current_best = min(results)
seen[x, y] = current_best
return current_best
You don't need to.
After get_path returns, start from 0,0 look for a move where seen[x', y'] = seen[x,y] - matrix[x,y].
If you have equality (both moves work) pick whatever you want (equals paths).
Keep going until you reach the end.

How do I identify the magnitude of the list of values ​and use different equations for different regions?

Code:
rho_list = np.arange(10000, dtype = 'float64') * 0.0002 * rhoe
F_rho_list = []
for rhoi in rho_list:
if 0.0 <= rhoi < rhol:
F_rho_list += [Fm0 + Fm1*(rhoi/rhol -1) + Fm2*np.power(rhoi/rhol -1, 2) + Fm3*np.power(rhoi/rhol -1, 3)]
elif rhol <= rhoi < rhon:
F_rho_list += [Fn0 + Fn1*(rhoi/rhon -1) + Fn2*np.power(rhoi/rhon -1, 2) + Fn3*np.power(rhoi/rhon -1, 3)]
elif rhon <= rhoi <rho0:
F_rho_list += [F0 + F1*(rhoi/rhoe -1) + F2*np.power(rhoi/rhoe -1, 2) + F3*np.power(rhoi/rhoe -1, 3)]
elif rhoi >= rho0:
F_rho_list += [Fe*(1- etha*np.log(rhoi/rhoe))*np.power(rhoi/rhoe, etha)]
rho_list is a list from 0 to 2*rhoe.
For different values or different regions, I want to use different equations to calculate F_rho value and put it into F_rho_list.
I know that I can use
F_rho_list[(rho_list>=0) & (rho_list<rhol)]
to pick numbers. However, I don't know how to insert those numbers into different equations.
Can anyone solve such problems more easily? Thanks in advance.
Here's a example that looks more structural. But I think the way you did it is already good enough to solve the problem.
def func1(x, left, right):
return x + 2
def func2(x, left, right):
return 2 * x
def func3(x, left, right):
return x - 3
funcs = [func1, func2, func3]
segments = [0, 1, 5, 10]
rho_list = np.linspace(0, 10, 10000)
F_rho_list = np.zeros_like(rho_list)
for left, right, func in zip(segments[:-1], segments[1:], funcs):
rng = (rho_list >= left) & (rho_list < right)
F_rho_list[rng] = func(rho_list[rng], left, right)

How to propagate two vectors u and v to fill a rectangle box in an efficient way

For illustration purpose, see image below.
Given a point p and two vectors u and v, we can get a linear combination of u and v, t = m*u + n*v, m and n are integer, and t should be within the box. Solve this problem is not too difficult. As m and n can both be positive and negative. It can be discussed:
m > 0 and n > 0
m > 0 and n < 0
m < 0 and n > 0
m < 0 and n < 0
Here is the python code for case 1:
m = 0
n = 0
t = m*u+n*v
x = t[0]
y = t[1]
l = []
while (x>0 and x < 1024 and y > 0 and y < 1024):
l.append(t)
m = m + 1
t = m*u+n*v
x = t[0]
y = t[1]
while (x>0 and x < 1024 and y > 0 and y < 1024):
l.append(t)
n = n +1
t = m*u+n*v
x = t[0]
y = t[1]
Using two loops for 4 sets may solve the problem.
Another way is generate too many points and then remove the points outside the box
I think maybe there is other simple and elegant way to do it?
Transform box into coordinate system defined with p as origin, and u as x direction of axis and v as direction of y axis. Result will be parallelogram. It is enough to find integer coordinates that are inside that parallelogram. That can be done by finding minimal and maximal m that is inside parallelogram, and searching for each m between minimal and maximal what range on n's are inside parallelogram.

python ProjectEuler task 4 Using while loop

i wanted to do the project euler problems by using python.
but i am having problems with the following task:
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 x 99.
Find the largest palindrome made from the product of two 3-digit numbers.
my code for the given task:
def palindrome_number():
n=0
lower_range = 100
upper_range = 999
while x >= lower_range or x <= upper_range and y >= lower_range or y <= upper_range:
z = x * y
while z > n:
s = str(x * y)
if s == s[::-1]:
n = x * y
print(n)
now i dont know how to check for all the x and y numbers varying from 100-999.
i thought it has to be like in my code, but it doesnt work
Solution 1: using a generator expression
Actually the problem can be solved in one line :)
max(x*y for x in range(100, 1000) for y in range(100, 1000) if str(x*y)==str(x*y)[::-1])
Solution 2: using a for loop
for loops are better suited for this kind of operation than while loops. Below is the solution (I have only replaced your while with two for loops. The first loop tells the variable x to run from 100 to 999 and the second one tells y to do the same. With these two loops you will try out all combinations for x and y.)
def palindrome_number():
n = 0
lower_range = 100
upper_range = 999
for x in range(lower_range, upper_range+1):
for y in range(lower_range, upper_range+1):
z = x * y
if z > n: # an *if* suffices ;)
s = str(x * y)
if s == s[::-1]:
n = x * y
print(n)
Solution 3: using a while loop
To get the same thing with while loops you would have to take care of changing x and y to get all combinations:
x = y = lower_range
while x >= lower_range and x <= upper_range: # (*and* instead of *or*)
while y >= lower_range and y <= upper_range: # (again you want the >= *and* the <= to be fulfilled)
z = x * y
if z > n:
s = str(x * y)
if s == s[::-1]:
n = x * y
y += 1 # change y to get all combinations
y = lower_range
x += 1 # change x to get all combinations

Checking if a point is inside negative box

I have made this little function for checking if a point is inside a selection box:
def select(x1, y1, w, h):
x, y = position
x2 = x1 + w
y2 = y1 + h
if x >= x1 and y >= y1:
if x <= x2 and y <= y2:
selected = True
else:
selected = False
But it only works if w and h are larger values than x1, and y1. For example, it doesn't work if the box has a negative size. How can I include checking those cases without a prior check of if w < x1 and h < y1?
Why not using the following checks:
if x >= min(x1,x2) and x <= max(x1,x2):
if y >= min(y1,y2) and y <= max(y1,y2):
...
You can find the minimum and maximum of the two numbers, and assign them to variables in one statement, using sorted(list) and destructuring assignment. Also note the use of min <= value <= max chained comparisons:
def select(x1, y1, w, h):
x, y = position
minX, maxX = sorted([x1, x1 + w])
minY, maxY = sorted([y1, y1 + h])
if minX <= x <= maxX and minY <= y <= maxY:
selected = True
else:
selected = False

Categories

Resources