在python当中的字典能让使用者快速找到对应的数据值,但是如果想要实现这样的一个字典:

1
2
3
4
_dict = {
[1,5):"a",
[5,10):"b"
}

能让操作者在仅知道一个数值就可以索引到范围对应的那个value,如_dict[3]输出"a"该怎么做呢?

解决办法

可以借助pythonbisect对字典进行重写解决该问题,bisect相关信息就不过多阐述了,简单来说就是通过排序算法,定位指定值在范围内的位置,再通过索引找到位置。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from bisect import bisect_left, bisect_right
from collections.abc import MutableMapping

class RangeBisection(MutableMapping):
def __init__(self, map=None):
self._upper = []
self._lower = []
self._values = []
if map is not None:
self.update(map)

def __len__(self):
return len(self._values)

def __getitem__(self, point_or_range):
if isinstance(point_or_range, tuple):
low, high = point_or_range
i = bisect_right(self._upper, high)
point = low
else:
point = point_or_range
i = bisect_right(self._upper, point)
if i >= len(self._values) or self._lower[i] > point:
raise IndexError(point_or_range)
return self._values[i]

def __setitem__(self, r, value):
lower, upper = r
i = bisect_right(self._upper, upper)
if i < len(self._values) and self._lower[i] < upper:
raise IndexError('No overlaps permitted')
self._upper.insert(i, upper)
self._lower.insert(i, lower)
self._values.insert(i, value)

def __delitem__(self, r):
lower, upper = r
i = bisect_right(self._upper, upper)
if self._upper[i] != upper or self._lower[i] != lower:
raise IndexError('Range not in map')
del self._upper[i]
del self._lower[i]
del self._values[i]

def __iter__(self):
yield from zip(self._lower, self._upper)

d = RangeBisection({
(0.0, 0.1): "a",
(0.1, 0.3): "b",
(0.3, 0.55): "c",
(0.55, 0.7): "d",
(0.7, 1.0): "e",})
d[0.0]