可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm refactoring a function that, given a series of endpoints that implicitly define intervals, checks if a number is included in the interval, and then return a corresponding (not related in any computable way).
The code that is now handling the work is:
if p <= 100:
return 0
elif p > 100 and p <= 300:
return 1
elif p > 300 and p <= 500:
return 2
elif p > 500 and p <= 800:
return 3
elif p > 800 and p <= 1000:
return 4
elif p > 1000:
return 5
Which is IMO quite horrible, and lacks in that both the intervals and the return values are hardcoded.
Any use of any data structure is of course possible.
回答1:
import bisect
bisect.bisect_left([100,300,500,800,1000], p)
回答2:
You could try a take on this:
def check_mapping(p):
mapping = [(100, 0), (300, 1), (500, 2)] # Add all your values and returns here
for check, value in mapping:
if p <= check:
return value
print check_mapping(12)
print check_mapping(101)
print check_mapping(303)
produces:
0
1
2
As always in Python, there will be any better ways to do it.
回答3:
It is indeed quite horrible. Without a requirement to have no hardcoding, it should have been written like this:
if p <= 100:
return 0
elif p <= 300:
return 1
elif p <= 500:
return 2
elif p <= 800:
return 3
elif p <= 1000:
return 4
else:
return 5
Here are examples of creating a lookup function, both linear and using binary search, with the no-hardcodings requirement fulfilled, and a couple of sanity checks on the two tables:
def make_linear_lookup(keys, values):
assert sorted(keys) == keys
assert len(values) == len(keys) + 1
def f(query):
return values[sum(1 for key in keys if query > key)]
return f
import bisect
def make_bisect_lookup(keys, values):
assert sorted(keys) == keys
assert len(values) == len(keys) + 1
def f(query):
return values[bisect.bisect_left(keys, query)]
return f
回答4:
Try something along the lines of:
d = {(None,100): 0,
(100,200): 1,
...
(1000, None): 5}
value = 300 # example value
for k,v in d.items():
if (k[0] is None or value > k[0]) and (k[1] is None or value <= k[1]):
return v
回答5:
Another way ...
def which(lst, p):
return len([1 for el in lst if p > el])
lst = [100, 300, 500, 800, 1000]
which(lst, 2)
which(lst, 101)
which(lst, 1001)
回答6:
def which_interval(endpoints, number):
for n, endpoint in enumerate(endpoints):
if number <= endpoint:
return n
previous = endpoint
return n + 1
Pass your endpoints as a list in endpoints
, like this:
which_interval([100, 300, 500, 800, 1000], 5)
Edit:
The above is a linear search. Glenn Maynard's answer will have better performance, since it uses a bisection algorithm.