Find three numbers with a given sum and product - python

Is it possible to write a Python program to find three numbers whose sum and product are given by the user? For example, 3 + 3 + 5 = 11 and 3 × 3 × 5 = 45, so if I give it 11 and 45, it should return (3, 3, 5).

The caveman approach (brute force with a miniscule amount of dynamic programming). MiTriPy's answer generalizes to n variables, although probably isn't more performant.
def solve(eqsum, eqprod):
solution_count = 0
for x in range(1, eqsum+1):
for y in range(1, eqsum+1-x):
for z in range(1, eqsum+1-x-y):
if x+y+z == eqsum:
if x*y*z == eqprod:
print(f"x={x} y={y} z={z}")
solution_count += 1
print(f"Found {solution_count} solutions.");
solve(eqsum=11, eqprod=45)

Made something fast and very clumsy:
import itertools
from numpy import prod
def find_subset_of_numbers(number, product):
subset_of_numbers = [x for x in range(1, number + 1)]
for x in range(1, number+1):
subset_of_numbers.append(x)
for x in range(1, number+1):
subset_of_numbers.append(x)
result = [seq for i in range(3, 0, -1)
for seq in itertools.combinations(subset_of_numbers, i)
if sum(seq) == number and len(seq) == 3 and prod(seq) == product]
return result
This will not handle duplicates very well but you could add another check for that:
print(find_subset_of_numbers(11, 45))
output: [(3, 5, 3), (3, 5, 3), (3, 3, 5), (3, 3, 5), (3, 5, 3), (3, 3, 5), (5, 3, 3), (3, 5, 3), (3, 3, 5)]

Here is a fairly efficient solution.
from collections.abc import Iterator
from math import sqrt
def solve(target_sum: int, target_prod: int) -> Iterator[tuple[int, int, int]]:
for x in range(1, target_sum):
if target_prod % x:
continue
midpoint = (target_sum - x) / 2
try:
radius = sqrt(midpoint ** 2 - target_prod // x)
except ValueError:
continue
y = midpoint + radius
if y.is_integer():
y = int(y)
z = int(midpoint - radius)
yield (x, y, z)
yield (x, y, z)
It uses the fact that if x + y = 2m and xy = p, then {x, y} = {m ± √(m² − p)}.

Related

sympy piecewise:i want to use array loop

sympy piecewise:i want use array loop
OK
from sympy import *
var('x')
myP1 = (0, x < -1)
myP2 = (x, x <= 1)
myP3 = (1, x >= 5)
myPw1= Piecewise( myP1,myP2,myP3 )
myPw2= Piecewise(*(myP1,myP2,myP3))
print("#",myPw1,myPw1.subs(x,6))
print("#",myPw2,myPw2.subs(x,6))
# Piecewise((0, x < -1), (x, x <= 1), (1, x >= 5)) 1
# Piecewise((0, x < -1), (x, x <= 1), (1, x >= 5)) 1
i want use array. (i want use Sum or use Append)
i want use array loop
TypeError
from sympy import *
var('x myP')
myP[1] = (0, x < -1)
myP[2] = (x, x <= 1)
myP[3] = (1, x >= 5)
myPw = Piecewise(*(myP[1] , myP[2] , myP[3]))
print("#",myPw,myPw.subs(x,6))
# myP[1] = (0, x < -1)
# TypeError: 'Symbol' object does not support item assignment
(2022-03-11)
i try tuple
from sympy import *
var('x')
myP=[]
myP=myP+list([(0, x < -1)])
myP=myP+list([(x, x <= 1)])
myP=myP+list([(1, x >= 5)])
myPw=Piecewise(*myP)
print("#",myPw)
myP=[]
myP=list([(0, x < -1)])+list([(x, x <= 1)])+list([(1, x >= 5)])
myPw=Piecewise(*myP)
print("#",myPw)
# Piecewise((0, x < -1), (x, x <= 1), (1, x >= 5))
# Piecewise((0, x < -1), (x, x <= 1), (1, x >= 5))
You created symbols x and myP and then you tried to treat myP like a list (or something indexable) by writing myP[1] = .... Instead, create a list and assign/append values:
>>> myP = []
>>> myP.append((0, x < -1))
>>> myP.append((x, x <= 1))
>>> myP.append((1, x >= 5))
>>> myPw = Piecewise(*myP)

Iterate over pairs in order of sum of absolute values

I want to iterate over pairs of integers in order of the sum of their absolute values. The list should look like:
(0,0)
(-1,0)
(0,1)
(0,-1)
(1,0)
(-2,0)
(-1,1)
(-1,-1)
(0,2)
(0,-2)
(1,1)
(1,-1)
(2,0)
[...]
For pairs with the same sum of absolute values I don't mind which order they come in.
Ideally I would like to be able to create the pairs forever so that I can use each one in turn. How can you do that?
For a fixed range I can make the list of pairs in an ugly way with:
sorted([(x,y)for x in range(-20,21)for y in range(-20,21)if abs(x)+abs(y)<21],key=lambda x:sum(map(abs,x))
This doesn't allow me to iterate forever and it also doesn't give me one pair at a time.
This seems to do the trick:
from itertools import count # Creates infinite iterator
def abs_value_pairs():
for absval in count(): # Generate all possible sums of absolute values
for a in range(-absval, absval + 1): # Generate all possible first values
b = abs(a) - absval # Compute matching second value (arbitrarily do negative first)
yield a, b
if b: # If first b is zero, don't output again, otherwise, output positive b
yield a, -b
This runs forever, and operates efficiently (avoiding recomputing anything unnecessarily).
This will do it. If you really want it to be infinite, remove the firs if statement.
import itertools
def makepairs(count=3):
yield (0,0)
for base in itertools.count(1):
if base > count: # optional escape
return # optional escape
for i in range(base+1):
yield (i, base-i)
if base != i:
yield (i, i-base)
if i:
yield (-i, base-i)
if base != i:
yield (-i, i-base)
print(list(makepairs(9)))
The solution below produces a sum stream with tuples of any length:
from itertools import count
def pairs(l = 2):
def groups(d, s, c = []):
if not d and sum(map(abs, c)) == s:
yield tuple(c)
elif d:
for i in [j for k in d[0] for j in {k, -1*k}]:
yield from groups(d[1:], s, c +[i])
for i in count():
yield from groups([range(i+1) for _ in range(l)], i)
p = pairs()
for _ in range(10):
print(next(p))
You could make an infinite generator function:
def pairSums(s = 0): # base generation on target sum to get pairs in order
while True: # s parameter allows starting from a given sum
for i in range(s//2+1): # partitions
yield from {(i,s-i),(s-i,i),(i-s,-i),(-i,i-s)} # no duplicates
s += 1 # next target sum
Output:
for p in pairSums(): print(p)
(0, 0)
(0, 1)
(0, -1)
(1, 0)
(-1, 0)
(2, 0)
(-2, 0)
(0, -2)
(0, 2)
(1, 1)
(-1, -1)
(3, 0)
(0, 3)
(0, -3)
(-3, 0)
(1, 2)
(-1, -2)
(2, 1)
...
First notice that you can lay your totals out in a grid for non-negative values:
x
3|3
2|23
1|123
0|0123
-+----
|0123y
Here we can see a pattern where the diagonals are your totals. Let's just trace some systematic line through them. The following shows an order you could walk through them:
x
3|6
2|37
1|148
0|0259
-+----
|0123y
Here the matrix contains the order of the iterations.
This solves your problem for non-negative values of x and y. To get the rest you can just negate x and y, making sure you don't do it for when they are zero. Something like this:
def generate_triplets(n):
yield 0, (0, 0)
for t in range(1, n + 1): # Iterate over totals t
for x in range(0, t + 1): # Iterate over component x
y = t - x # Calclulate component y
yield t, (x, y) # Default case is non-negative
if y > 0:
yield t, (x, -y)
if x > 0:
yield t, (-x, y)
if x > 0 and y > 0:
yield t, (-x, -y)
def generate_pairs(n):
yield from (pair for t, pair in generate_triplets(n))
# for pair in generate_pairs(10):
# print(pair)
for t, (x, y) in generate_triplets(3):
print(f'{t} = abs({x}) + abs({y})')
This outputs
0 = abs(0) + abs(0)
1 = abs(0) + abs(1)
1 = abs(0) + abs(-1)
1 = abs(1) + abs(0)
1 = abs(-1) + abs(0)
2 = abs(0) + abs(2)
2 = abs(0) + abs(-2)
2 = abs(1) + abs(1)
2 = abs(1) + abs(-1)
2 = abs(-1) + abs(1)
2 = abs(-1) + abs(-1)
2 = abs(2) + abs(0)
2 = abs(-2) + abs(0)
3 = abs(0) + abs(3)
3 = abs(0) + abs(-3)
3 = abs(1) + abs(2)
3 = abs(1) + abs(-2)
3 = abs(-1) + abs(2)
3 = abs(-1) + abs(-2)
3 = abs(2) + abs(1)
3 = abs(2) + abs(-1)
3 = abs(-2) + abs(1)
3 = abs(-2) + abs(-1)
3 = abs(3) + abs(0)
3 = abs(-3) + abs(0)
Or as pairs:
(0, 0)
(0, 1)
(0, -1)
(1, 0)
(-1, 0)
(0, 2)
(0, -2)
(1, 1)
(1, -1)
(-1, 1)
(-1, -1)
(2, 0)
(-2, 0)
...
For each sum, walk the diagonal in one quadrant and rotate each coordinate into the other quadrants:
from itertools import count
def coordinates():
yield 0, 0
for sum in count(1):
for x in range(sum):
y = sum - x
yield x, y
yield y, -x
yield -x, -y
yield -y, x
(I hope I understood the requirements) I used itertools product:
>>> for i in sorted(itertools.product(range(-5, 4), range(-5, 4)), key=lambda tup: abs(tup[0]) + abs(tup[1])):
print(i)
...
(0, 0)
(-1, 0)
(0, -1)
(0, 1)
(1, 0)
(-2, 0)
(-1, -1)
(-1, 1)
(0, -2)
(0, 2)
(1, -1)
(1, 1)
(2, 0)
(-3, 0)
(-2, -1)
(-2, 1)
(-1, -2)
(-1, 2)
(0, -3)
(0, 3)
(1, -2)
(1, 2)
(2, -1)
...

Python: Set X and Set Y all mappings injective and surjective

Set X and Set Y all mappings->
(without imports)
x=[0, 1],Y=[1,2]
=
[[(0, 1), (1, 1)],
[(0, 2), (1, 1)],
[(0, 1), (1, 2)],
[(0, 2), (1, 2)]]
def maps(X, Y):
if X==[]:
return [[]]
if X!=[] and Y==[]:
return Y
def product(*args, repeat=1):
pools = [tuple(pool) for pool in args] * repeat
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
e=[]
for i in product(*([Y]*len(X))):
e.append(list(zip(X, i)))
return e
this is what i have now but i want this for injective and surjective once so def mapinjective and def surjective
You could use list comprehensions to filter the list of all possible mappings returned by the function you already have, e.g.
def maps_surjective(X, Y):
return [f for f in maps(X, Y) if set(y for x, y in f) == set(Y)]
def maps_injective(X, Y):
return [f for f in maps(X, Y) if len(set(y for x, y in f)) == len(X)]

Closest Pair Implemetation Python

I am trying to implement the closest pair problem in Python using divide and conquer, everything seems to work fine except that in some input cases, there is a wrong answer. My code is as follows:
def closestSplitPair(Px,Py,d):
X = Px[len(Px)-1][0]
Sy = [item for item in Py if item[0]>=X-d and item[0]<=X+d]
best,p3,q3 = d,None,None
for i in xrange(0,len(Sy)-2):
for j in xrange(1,min(7,len(Sy)-1-i)):
if dist(Sy[i],Sy[i+j]) < best:
best = (Sy[i],Sy[i+j])
p3,q3 = Sy[i],Sy[i+j]
return (p3,q3,best)
I am calling the above function through a recursive function which is as follows:
def closestPair(Px,Py): """Px and Py are input arrays sorted according to
their x and y coordinates respectively"""
if len(Px) <= 3:
return min_dist(Px)
else:
mid = len(Px)/2
Qx = Px[:mid] ### x-sorted left side of P
Qy = Py[:mid] ### y-sorted left side of P
Rx = Px[mid:] ### x-sorted right side of P
Ry = Py[mid:] ### y-sorted right side of P
(p1,q1,d1) = closestPair(Qx,Qy)
(p2,q2,d2) = closestPair(Rx,Ry)
d = min(d1,d2)
(p3,q3,d3) = closestSplitPair(Px,Py,d)
return min((p1,q1,d1),(p2,q2,d2),(p3,q3,d3),key=lambda tup: tup[2])
where min_dist(P) is the brute force implementation of the closest pair algorithm for a list P having 3 or less elements and returns a tuple containing the pair of closest points and their distance.
If my input is P = [(0,0),(7,6),(2,20),(12,5),(16,16),(5,8),(19,7),(14,22),(8,19),(7,29),(10,11),(1,13)], then my output is ((5,8),(7,6),2.8284271) which is the correct output. But when my input is P = [(94, 5), (96, -79), (20, 73), (8, -50), (78, 2), (100, 63), (-14, -69), (99, -8), (-11, -7), (-78, -46)] the output I get is ((78, 2), (94, 5), 16.278820596099706) whereas the correct output should be ((94, 5), (99, -8), 13.92838827718412)
You have two problems, you are forgetting to call dist to update the best distance. But the main problem is there is more than one recursive call happening so you can end up overwriting when you find a closer split pair with the default, best,p3,q3 = d,None,None. I passed the best pair from closest_pair as an argument to closest_split_pair so I would not potentially overwrite the value.
def closest_split_pair(p_x, p_y, delta, best_pair): # <- a parameter
ln_x = len(p_x)
mx_x = p_x[ln_x // 2][0]
s_y = [x for x in p_y if mx_x - delta <= x[0] <= mx_x + delta]
best = delta
for i in range(len(s_y) - 1):
for j in range(1, min(i + 7, (len(s_y) - i))):
p, q = s_y[i], s_y[i + j]
dst = dist(p, q)
if dst < best:
best_pair = p, q
best = dst
return best_pair
The end of closest_pair looks like the following:
p_1, q_1 = closest_pair(srt_q_x, srt_q_y)
p_2, q_2 = closest_pair(srt_r_x, srt_r_y)
closest = min(dist(p_1, q_1), dist(p_2, q_2))
# get min of both and then pass that as an arg to closest_split_pair
mn = min((p_1, q_1), (p_2, q_2), key=lambda x: dist(x[0], x[1]))
p_3, q_3 = closest_split_pair(p_x, p_y, closest,mn)
# either return mn or we have a closer split pair
return min(mn, (p_3, q_3), key=lambda x: dist(x[0], x[1]))
You also have some other logic issues, your slicing logic is not correct, I made some changes to your code where brute is just a simple bruteforce double loop:
def closestPair(Px, Py):
if len(Px) <= 3:
return brute(Px)
mid = len(Px) / 2
# get left and right half of Px
q, r = Px[:mid], Px[mid:]
# sorted versions of q and r by their x and y coordinates
Qx, Qy = [x for x in q if Py and x[0] <= Px[-1][0]], [x for x in q if x[1] <= Py[-1][1]]
Rx, Ry = [x for x in r if Py and x[0] <= Px[-1][0]], [x for x in r if x[1] <= Py[-1][1]]
(p1, q1) = closestPair(Qx, Qy)
(p2, q2) = closestPair(Rx, Ry)
d = min(dist(p1, p2), dist(p2, q2))
mn = min((p1, q1), (p2, q2), key=lambda x: dist(x[0], x[1]))
(p3, q3) = closest_split_pair(Px, Py, d, mn)
return min(mn, (p3, q3), key=lambda x: dist(x[0], x[1]))
I just did the algorithm today so there are no doubt some improvements to be made but this will get you the correct answer.
Here is a recursive divide-and-conquer python implementation of the closest point problem based on the heap data structure. It also accounts for the negative integers. It can return the k-closest point by popping k nodes in the heap using heappop().
from __future__ import division
from collections import namedtuple
from random import randint
import math as m
import heapq as hq
def get_key(item):
return(item[0])
def closest_point_problem(points):
point = []
heap = []
pt = namedtuple('pt', 'x y')
for i in range(len(points)):
point.append(pt(points[i][0], points[i][1]))
point = sorted(point, key=get_key)
visited_index = []
find_min(0, len(point) - 1, point, heap, visited_index)
print(hq.heappop(heap))
def find_min(start, end, point, heap, visited_index):
if len(point[start:end + 1]) & 1:
mid = start + ((len(point[start:end + 1]) + 1) >> 1)
else:
mid = start + (len(point[start:end + 1]) >> 1)
if start in visited_index:
start = start + 1
if end in visited_index:
end = end - 1
if len(point[start:end + 1]) > 3:
if start < mid - 1:
distance1 = m.sqrt((point[start].x - point[start + 1].x) ** 2 + (point[start].y - point[start + 1].y) ** 2)
distance2 = m.sqrt((point[mid].x - point[mid - 1].x) ** 2 + (point[mid].y - point[mid - 1].y) ** 2)
if distance1 < distance2:
hq.heappush(heap, (distance1, ((point[start].x, point[start].y), (point[start + 1].x, point[start + 1].y))))
else:
hq.heappush(heap, (distance2, ((point[mid].x, point[mid].y), (point[mid - 1].x, point[mid - 1].y))))
visited_index.append(start)
visited_index.append(start + 1)
visited_index.append(mid)
visited_index.append(mid - 1)
find_min(start, mid, point, heap, visited_index)
if mid + 1 < end:
distance1 = m.sqrt((point[mid].x - point[mid + 1].x) ** 2 + (point[mid].y - point[mid + 1].y) ** 2)
distance2 = m.sqrt((point[end].x - point[end - 1].x) ** 2 + (point[end].y - point[end - 1].y) ** 2)
if distance1 < distance2:
hq.heappush(heap, (distance1, ((point[mid].x, point[mid].y), (point[mid + 1].x, point[mid + 1].y))))
else:
hq.heappush(heap, (distance2, ((point[end].x, point[end].y), (point[end - 1].x, point[end - 1].y))))
visited_index.append(end)
visited_index.append(end - 1)
visited_index.append(mid)
visited_index.append(mid + 1)
find_min(mid, end, point, heap, visited_index)
x = []
num_points = 10
for i in range(num_points):
x.append((randint(- num_points << 2, num_points << 2), randint(- num_points << 2, num_points << 2)))
closest_point_problem(x)
:)
Brute force can work faster with stdlib functions. Therefore, it can be effectively applied to more than 3 points.
from itertools import combinations
def closest(points_list):
return min((dist(p1, p2), p1, p2)
for p1, p2 in combinations(points_list, r=2))
The most effective way to divide the points is to divide them on tiles. If you don't have outliers, you can just split your space on equal parts and compare points only in the same or in the neighbour tiles.
Number of tiles must be as large as it possible. But, to avoid isolated tiles, when each point doesn't have points in neighbour tiles, you must limit number of tiles by the number of points.
Full listing:
from math import sqrt
from itertools import combinations, product
from collections import defaultdict
import sys
max_float = sys.float_info.max
def dist((x1, y1), (x2, y2)):
return sqrt((x1 - x2) ** 2 + (y1 - y2) **2)
def closest(points_list):
if len(points_list) < 2:
return (max_float, None, None) # default value compatible with min function
return min((dist(p1, p2), p1, p2)
for p1, p2 in combinations(points_list, r=2))
def closest_between(pnt_lst1, pnt_lst2):
if not pnt_lst1 or not pnt_lst2:
return (max_float, None, None) # default value compatible with min function
return min((dist(p1, p2), p1, p2)
for p1, p2 in product(pnt_lst1, pnt_lst2))
def divide_on_tiles(points_list):
side = int(sqrt(len(points_list))) # number of tiles on one side of square
tiles = defaultdict(list)
min_x = min(x for x, y in points_list)
max_x = max(x for x, y in points_list)
min_y = min(x for x, y in points_list)
max_y = max(x for x, y in points_list)
tile_x_size = float(max_x - min_x) / side
tile_y_size = float(max_y - min_y) / side
for x, y in points_list:
x_tile = int((x - min_x) / tile_x_size)
y_tile = int((y - min_y) / tile_y_size)
tiles[(x_tile, y_tile)].append((x, y))
return tiles
def closest_for_tile(tiles, (x_tile, y_tile)):
points = tiles[(x_tile, y_tile)]
return min(closest(points),
# use dict.get to avoid creating empty tiles
# we compare current tile only with half of neighbours (right/top),
# because another half (left/bottom) make it in another iteration by themselves
closest_between(points, tiles.get((x_tile+1, y_tile))),
closest_between(points, tiles.get((x_tile, y_tile+1))),
closest_between(points, tiles.get((x_tile+1, y_tile+1))),
closest_between(points, tiles.get((x_tile-1, y_tile+1))))
def find_closest_in_tiles(tiles):
return min(closest_for_tile(tiles, coord) for coord in tiles.keys())
P1 = [(0,0),(7,6),(2,20),(12,5),(16,16),(5,8),(19,7),(14,22),(8,19),(7,29),(10,11),(1,13)]
P2 = [(94, 5), (96, -79), (20, 73), (8, -50), (78, 2), (100, 63), (-14, -69), (99, -8), (-11, -7), (-78, -46)]
print find_closest_in_tiles(divide_on_tiles(P1)) # (2.8284271247461903, (7, 6), (5, 8))
print find_closest_in_tiles(divide_on_tiles(P2)) # (13.92838827718412, (94, 5), (99, -8))
print find_closest_in_tiles(divide_on_tiles(P1 + P2)) # (2.8284271247461903, (7, 6), (5, 8))
You just need to change the seventh line in your closestSplitPair function def from best=(Sy[i],Sy[i+j]) to best=dist(Sy[i],Sy[i+j]) and you will get the correct answer: ((94, 5), (99, -8), 13.92838827718412). You were missing the calling to the dist function.
This was pointed out by Padraic Cunningham's answer as the first problem.
Best Regards.

Determining neighbours of cell two dimensional list

I have a list of lists, something like
[[1, 2, 3,],[4, 5, 6,],[7, 8, 9]].
Represented graphically as:
1 2 3
4 5 6
7 8 9
I'm looking for an elegant approach to check the value of neighbours of a cell, horizontally, vertically and diagonally. For instance, the neighbours of [0][2] are [0][1], [1][1] and [1][2] or the numbers 2, 5, 6.
Now I realise, I could just do a bruteforce attack checking every value a la:
[i-1][j]
[i][j-1]
[i-1][j-1]
[i+1][j]
[i][j+1]
[i+1][j+1]
[i+1][j-1]
[i-1][j+1]
But thats easy, and I figured I can learn more by seeing some more elegant approaches.
# Size of "board"
X = 10
Y = 10
neighbors = lambda x, y : [(x2, y2) for x2 in range(x-1, x+2)
for y2 in range(y-1, y+2)
if (-1 < x <= X and
-1 < y <= Y and
(x != x2 or y != y2) and
(0 <= x2 <= X) and
(0 <= y2 <= Y))]
>>> print(neighbors(5, 5))
[(4, 4), (4, 5), (4, 6), (5, 4), (5, 6), (6, 4), (6, 5), (6, 6)]
I don't know if this is considered clean, but this one-liner gives you all neighbors by iterating over them and discarding any edge cases.
Assuming you have a square matrix:
from itertools import product
size = 3
def neighbours(cell):
for c in product(*(range(n-1, n+2) for n in cell)):
if c != cell and all(0 <= n < size for n in c):
yield c
Using itertools.product and thanks to Python's yield expression and star operator, the function is pretty dry but still readable enough.
Given a matrix size of 3, you can then (if needed) collect the neighbours in a list:
>>> list(neighbours((2,2)))
[(1, 1), (1, 2), (2, 1)]
What the function does can be visualized as follows:
mb...
from itertools import product, starmap
x, y = (8, 13)
cells = starmap(lambda a,b: (x+a, y+b), product((0,-1,+1), (0,-1,+1)))
// [(8, 12), (8, 14), (7, 13), (7, 12), (7, 14), (9, 13), (9, 12), (9, 14)]
print(list(cells)[1:])
for x_ in range(max(0,x-1),min(height,x+2)):
for y_ in range(max(0,y-1),min(width,y+2)):
if (x,y)==(x_,y_): continue
# do stuff with the neighbours
>>> a=[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> width=height=3
>>> x,y=0,2
>>> for x_ in range(max(0,x-1),min(height,x+2)):
... for y_ in range(max(0,y-1),min(width,y+2)):
... if (x,y)==(x_,y_): continue
... print a[x_][y_]
...
2
5
6
If someone is curious about alternative way to pick direct (non-diagonal) neighbors, here you go:
neighbors = [(x+a[0], y+a[1]) for a in
[(-1,0), (1,0), (0,-1), (0,1)]
if ( (0 <= x+a[0] < w) and (0 <= y+a[1] < h))]
There's no cleaner way to do this. If you really want you could create a function:
def top(matrix, x, y):
try:
return matrix[x][y - 1];
except IndexError:
return None
Here is your list:
(x - 1, y - 1) (x, y - 1) (x + 1, y - 1)
(x - 1, y) (x, y) (x + 1, y)
(x - 1, y + 1) (x, y + 1) (x + 1, y + 1)
So the horizontal neighbors of (x, y) are (x +/- 1, y).
The vertical neighbors are (x, y +/- 1).
Diagonal neighbors are (x +/- 1, y +/- 1).
These rules apply for an infinite matrix.
To make sure the neighbors fit into a finite matrix, if the initial (x, y) is at the edge, just apply one more restriction to the coordinates of neighbors - the matrix size.
>>> import itertools
>>> def sl(lst, i, j):
il, iu = max(0, i-1), min(len(lst)-1, i+1)
jl, ju = max(0, j-1), min(len(lst[0])-1, j+1)
return (il, iu), (jl, ju)
>>> lst = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> tup = 0, 2
>>> [lst[i][j] for i, j in itertools.product(*sl(lst, *tup)) if (i, j) != tup]
[2, 5, 6]
I don't know how elegant it seems to you, but it seems to work w/o any hard-coding.
This generates all indices:
def neighboring( array ):
nn,mm = len(array), len(array[0])
offset = (0,-1,1) # 0 first so the current cell is the first in the gen
indices = ( (i,j) for i in range(nn) for j in range(mm) )
for i,j in indices:
all_neigh = ( (i+x,j+y) for x in offset for y in offset )
valid = ( (i,j) for i,j in all_neigh if (0<=i<nn) and (0<=j<mm) ) # -1 is a valid index in normal lists, but not here so throw it out
yield valid.next(), valid ## first is the current cell, next are the neightbors
for (x,y), neigh in neighboring( l ):
print l[x][y], [l[x][y] for x,y in neigh]
If lambdas daunt you here you are .But lambdas make your code look clean.#johniek_comp has a very clean solution TBH
k,l=(2,3)
x = (0,-1,+1)
y = (0,-1,+1)
cell_u = ((k+a,l+b) for a in x for b in y)
print(list(cell_u))
Inspired by one of the previous answers.
You can use min() and max() functions to shorten the calculations:
width = 3
height = 3
[(x2, y2) for x2 in range(max(0, x-1), min(width, x+2))
for y2 in range(max(0, y-1), min(height, y+2))
if (x2, y2) != (x, y)]
Thank you to #JS_is_bad for a great hint about the neighbors. Here is the running code for this problem:
def findNeighbours(l,elem):
#This try is for escaping from unbound error that happens
#when we try to iterate through indices that are not in array
try:
#Iterate through each item of multidimensional array using enumerate
for row,i in enumerate(l):
try:
#Identifying the column index of the givem element
column=i.index(elem)
except ValueError:
continue
x,y=row,column
# hn=list(((x,y+1),(x,y-1))) #horizontal neighbours=(x,y+/-1)
# vn=list(((x+1,y),(x-1,y))) #vertical neighbours=(x+/-1,y)
# dn=list(((x+1,y+1),(x-1,y-1),(x+1,y-1),(x-1,y+1))) #diagonal neighbours=(x+/-1,y+/-1)
#Creating a list with values that are actual neighbors for the extracted index of array
neighbours=[(x,y+1),(x,y-1),(x+1,y),(x-1,y),(x+1,y+1),(x-1,y-1),(x+1,y-1),(x-1,y+1)]
#Creating a universe of indices from given array
index_list=[(i,j) for i in range(len(l)) for j in range(len(l[i]))]
#Looping through index_list and nested loop for neighbours but filter for matched ones
# and extract the value of respective index
return_values=[l[index[0]][index[1]] for index in index_list for neighbour in neighbours if index==neighbour]
return return_values,neighbours
except UnboundLocalError:
return []
Inspired by johniek's answer here is my solution which also checks for boundaries.
def get_neighbours(node, grid_map):
row_index, col_index = node
height, width = len(grid_map), len(grid_map[0])
cells = list(starmap(lambda a, b: (row_index + a, col_index + b), product((0, -1, +1), (0, -1, +1))))
cells.pop(0) # do not include original node
cells = list(filter(lambda cell: cell[0] in range(height) and cell[1] in range(width), cells))
return cells
def numCells(grid):
x=len(grid)
y=len(grid[0])
c=0
for i in range(x):
for j in range(y):
value_=grid[i][j]
f=1
for i2 in range(max(0,i-1),min(x,i+2)):
for j2 in range(max(0,j-1),min(y,j+2)):
if (i2,j2) != (i,j) and value_<=grid[i2][j2]:
flag=0
break
if flag ==0:
break
else:
c+=1
return c
def getNeighbors(matrix: list, point: tuple):
neighbors = []
m = len(matrix)
n = len(matrix[0])
x, y = point
for i in range (x -1, x +2): #prev row to next row
for j in range(y - 1, y +2): #prev column to next col
if (0 <= i < m) and (0 <= j < n):
neighbors.append((i,j))
return neighbors
maybe you are checking a sudoku box. If the box is n x n and current cell is (x,y) start checking:
startingRow = x / n * n;
startingCol = y/ n * n

Categories