Python: Mapping from intervals to values
我正在重构一个函数,该函数给定一系列隐式定义间隔的端点,检查间隔中是否包含数字,然后返回相应的(不以任何可计算的方式相关)。现在处理工作的代码是:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
这是我非常可怕的,缺乏在间隔和返回值都是硬编码。当然,任何数据结构的使用都是可能的。
1 2 | import bisect bisect.bisect_left([100,300,500,800,1000], p) |
这里的医生:平分
这确实很可怕。如果没有要求没有硬编码,那么应该这样写:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
以下是创建查找函数的示例,包括线性搜索和使用二进制搜索,但没有满足硬编码要求,并且对两个表进行了一些健全性检查:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
你可以试试这个:
1 2 3 4 5 6 7 8 9 10 | 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) |
生产:
1 2 3 | 0 1 2 |
就像在Python中一样,有更好的方法可以做到这一点。
另一种方式…
1 2 3 4 5 6 7 | 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) |
1 2 3 4 5 6 | def which_interval(endpoints, number): for n, endpoint in enumerate(endpoints): if number <= endpoint: return n previous = endpoint return n + 1 |
在
1 | which_interval([100, 300, 500, 800, 1000], 5) |
编辑:
上面是一个线性搜索。格伦·梅纳德的答案将有更好的性能,因为它使用了二分法算法。
尝试以下方法:
1 2 3 4 5 6 7 8 | 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 |