Simplify proximity function using fewer ors & ands?

Question:

Both p and s are tuples with values like (1,9), (4,7), (5,6), etc.
The function checks if a node is close to another node (exactly one unit away) to find the best path.

def prox(p,s):
    if (p[0]==s[0]+1 and p[1]==s[1]) or (p[0]==s[0]-1 and p[1]==s[1]) or (p[1]==s[1]+1 and p[0]==s[0])  or (p[1]==s[1]-1 and p[0]==s[0]) or (p[0]+1==s[0] and p[1]==s[1])  or (p[0]-1==s[0] and p[1]==s[1]) or (p[1]+1==s[1] and p[0]==s[0]) or (p[1]-1==s[1]  and p[0]==s[0]):
        return True
    else:
        return False

It works fine but I feel like there’s a better way to write it.

Asked By: Paulo Corrêa

||

Answers:

Pls check the following code, I checked the conditions carefully so I believe constraint haven’t changed.

First option :

def prox(p,s):
    if abs(p[0]-s[0]) <= 1 and abs(p[1]-s[1]) <= 1:
        return True
    else:
        return False

You said you are new to python, so if it might confusing there’s that option as well
Second option :

def prox(p,s):
    if (p[0] in [s[0]+1, s[0]-1] and p[1]==s[1]) or (p[1] in [s[1]+1, s[1]-1] and p[0]==s[0]):
        return True
    else:
        return False
Answered By: NitzanTomer
def prox(p, s):
  return (abs(p[0] - s[0]) + abs(p[1] - s[1]) == 1)

This function checks if two points are neighbors in a 2D grid where movement is only allowed in four cardinal directions (north, south, east, west). The proximity is determined by calculating the Manhattan distance between two points. The Manhattan distance (also known as L1 distance) is the sum of absolute differences of the x and y coordinates of two points. The function returns True if the Manhattan distance between p and s is equal to 1 (i.e., adjacent).

Answered By: BigBrownBear00

Let’s do this a little at a time. You’re new to Python, so if you don’t understand all the tools used here, that’s fine! I’d recommend picking the most concise code that you personally still find readable at this point. I’ve provided links to learn more about the builtins and language constructs used.

First of all, you’re using this classic antipattern:

if boolean_condition:
    return True
else:
    return False

boolean_condition is already True or False, so anytime you see this structure, you can simplify it to just:

return boolean_condition

That already gets us down to:

def prox(p, s):
   return ((p[0]==s[0]+1 and p[1]==s[1]) or
           (p[0]==s[0]-1 and p[1]==s[1]) or
           (p[1]==s[1]+1 and p[0]==s[0]) or
           (p[1]==s[1]-1 and p[0]==s[0]) or
           (p[0]+1==s[0] and p[1]==s[1]) or
           (p[0]-1==s[0] and p[1]==s[1]) or
           (p[1]+1==s[1] and p[0]==s[0]) or
           (p[1]-1==s[1] and p[0]==s[0]))

(Broken up onto multiple lines by enclosing in parentheses, to make it more readable)

Now, you want to check if the distance between the two nodes is exactly 1, correct? So either the x or y coordinates need to be one apart, but not both. That means that if you subtract the two xs and take the absolute value of that difference, then do the same for the ys, then add the two differences, it should equal 1.

We could start by writing this as a for loop with zip to iterate through both tuples together, adding up the absolute value of differences:

def prox(p, s):
    total_difference = 0
    for first, second in zip(p, s):
        total_difference += abs(first - second)
    return total_difference == 1

This can be condensed using Python’s built-in sum function and a generator expression:

def prox(p, s):
    total_difference = sum(abs(first - second) for first, second in zip(p, s))
    return total_difference == 1

Or, skipping the intermediate variable:

def prox(p, s):
    return sum(abs(first - second) for first, second in zip(p, s)) == 1

Bonus: this same function generalizes to three (or any number of) dimensions. Probably not useful in this case, but neat.

Answered By: CrazyChucky
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.