How can this verbose, fearless routine be improved?

Is there a more pythonic way to do this? I am trying to find eight neighbors of an integer coordinate lying within. I am interested in reducing its verbosity without sacrificing speed.

def fringe8((px, py), (x1, y1, x2, y2)): f = [(px - 1, py - 1), (px - 1, py), (px - 1, py + 1), (px, py - 1), (px, py + 1), (px + 1, py - 1), (px + 1, py), (px + 1, py + 1)] f_inrange = [] for fx, fy in f: if fx < x1: continue if fx >= x2: continue if fy < y1: continue if fy >= y2: continue f_inrange.append((fx, fy)) return f_inrange 
+4
source share
11 answers

Here I take care of clearing the code:

Edit: I took David code in my answer to make it even more compact (and faster runtime).

 >>> from itertools import product >>> >>> def fringe8((px, py), (x1, y1, x2, y2)): ... f = [(px+dx, py+dy) for (dx, dy) in product((-1,0,1),(-1,0,1)) if (dx, dy) != (0, 0)] ... f_inrange = [(fx, fy) for (fx, fy) in f if x1 <= fx < x2 and y1 <= fy < y2] ... return f_inrange ... >>> fringe8((2, 2), (1, 1, 3, 3)) [(1, 1), (1, 2), (2, 1)] 

Edit: If you are not too comfortable understanding the list, feel free to break it down into a for loop. The conditions offered here and the answers of others are more understandable to you.

After all, the goal of achieving a list is to simplify reading, not verbose.

Edit again: Also see Ryan Ginstrom's answer .

+11
source

This is a recast of Xavier Ho's answer. I think this made a little clearer using the intermediate steps.

 from itertools import product def fringe8((px, py), (x1, y1, x2, y2)): nonzero = (pair for pair in product((-1,0,1),(-1,0,1)) if pair != (0, 0)) f = ((px+dx, py+dy) for (dx,dy) in nonzero) def in_range((fx, fy)): return x1 <= fx < x2 and y1 <= fy < y2 return [pair for pair in f if in_range(pair)] print fringe8((2, 2), (1, 1, 3, 3)) 
+8
source

Here is a thought:

 def fringe8((px, py), (x1, y1, x2, y2)): f = [(px + dx, py + dy) for (dx, dy) in itertools.product((-1,0,1),repeat=2) if not (dx == dy == 0)] f_inrange = [(fx, fy) for (fx, fy) in f if x1 <= fx < x2 and y1 <= fy < y2] return f_inrange 
+6
source

This list comprehension should work

 f_inrange = [(px+i,py+j) for i in (-1,0,1) for j in (-1,0,1) \ if (i != j or i != 0) and x1 <= px+i < x2 and \ y2 > py+j >= y1] 

although it is quite long.

+5
source

Here are my efforts. It directly constructs interesting ranges, so it does not check redundant points (except for the annoying center point). I added an extra argument r, which can return a large square around the point.

 def fringe((px, py), (x1, y1, x2, y2), r=1): return [(x, y) for x in xrange(max(px - r, x1), min(px + r + 1, x2)) for y in xrange(max(py - r, y1), min(py + r + 1, y2)) if x != px or y != py] 
+3
source
 def fringe8((px, py), (x1, y1, x2, y2)): return [(x, y) for x,y in itertools.product( [xi+px for xi in [-1,0,1]], [yi+py for yi in [-1,0,1]] ) if (x1<=x<x2) and (y1<=y<y2) and not ((x==px) and (y==py))] 

I don’t know if it was more pythonic, but it is definitely a different way to do it.

+2
source
 def fringe8((px, py), (x1, y1, x2, y2)): return [(fx, fy) for fx in [px - x for x in [-1, 0, 1]] if (fx >= x1 and fx < x2) for fy in [py - y for y in [-1, 0, 1]] if fy >= y1 and fy < y2 and not(fx == px and fy == py)] 
+2
source

I do not know from pythonicness, but I see that this function performs two things: a) finding adjacent points; and b) restricting the list of points to those within range. Therefore, I would share it because it was more clear; b) sometimes I may need one of these behaviors without the other; c) easier to test; and d) it is easier to name. I will not try to convert this advice into python - I am sure that my attempt will not be pleasant, but it will be my starting point.

+1
source

I like Carl's suggestion. You can also avoid re-building adjacent offsets.

 from itertools import product NEIGHBOR_OFFSETS = [pair for pair in product((-1,0,1), (-1,0,1)) if pair != (0, 0)] def clip(points, (x1, y1, x2, y2)): return [(px, py) for px, py in points if x1 <= px < x2 and y1 <= py < y2] def neighbors(px, py): return [(px+dx, py+dy) for dx, dy in NEIGHBOR_OFFSETS] def fringe8(point, rect): return clip(neighbors(*point), rect) 
+1
source

here is my disposal:

 def fringe8((px, py), (x1, y1, x2, y2)): return [(x, y) for x,y in itertools.product((px-1, px , px+1), (py-1, py , py+1)) if (x1<=x<x2) and (y1<=y<y2) and (x,y) != (px,py)] 
0
source

The name of the function may be more informative. I know what the code does, but I have no idea what it is for.

0
source

Source: https://habr.com/ru/post/1309842/


All Articles