mk8efz - 1 year ago 82
Python Question

# Simple, ugly function to produce an orientation from an angle.

I wrote a function that takes a degree and returns the orientation as 'N', 'NE', ...etc. Very simple, but it's ugly - is there any way to rewrite this to make it...prettier?

``````def orientation(tn):
if 23 <= tn <= 67:
o = 'NE'
elif 68 <= tn <= 113:
o = 'E'
elif 114 <= tn <= 158:
o = 'SE'
elif 159 <= tn <= 203:
o = 'S'
elif 204 <= tn <= 248:
o = 'SW'
elif 249 <= tn <= 293:
o = 'W'
elif 294 <= tn <= 338:
o = 'NW'
else:
o = 'N'
return o
``````

Use bisection:

``````from bisect import bisect_left

directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N']
boundaries = [22,  67,   113, 158,  203, 248,  293, 338,  360]

def orientation(tn):
return directions[bisect_left(boundaries, tn)]
``````

`bisect_left()` (very efficiently) finds the index into which you'd insert `tn` into the `boundaries` list; that index is then mapped into the `directions` list to translate to a string.

Bisection only takes up to 4 steps to find the right boundary (`log2(len(boundaries))`).

You could also add 22 and divide the value modulo 360 by 45:

``````directions = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N']

def orientation(tn):
index = ((tn + 22) % 360) // 45
return directions[index]
``````

However, your original boundaries were not evenly distributed at 45 degrees each, so this gives a slightly different result (your `N` boundaries span 44 degrees, while `E` is allotted 46 degrees). Bisection doesn't care about such exceptions; you can shift the boundaries all you like.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download