我应该保持范围(具有不同的间隔)和如下的值:
我该如何储存?像{'0': 1234, '5001': 1231, '10001': 3242, ...}
这样的词组?
存储后,我需要搜索相应值,但它应该查找范围 - 例如,6000
应该返回1231
。如果我将其存储为dict,我该如何执行搜索?
UPD。间隔中没有间隙,范围数量非常小(~50)。
答案 0 :(得分:3)
我建议您将其存储为词典列表,因为:
Explicit is better than implicit.
>>> rang = [{'start': 0, 'end': 5000, 'id': 1234}, {'start': 5000, 'end': 10000, 'id': 1231}, {'start': 10001, 'end': 20000, 'id': 342}]
>>> num = 10
>>> for r in rang:
... if r['start'] < num < r['end']:
... print r['id']
...
1234
>>> num = 10500
>>> for r in rang:
... if r['start'] < num < r['end']:
... print r['id']
...
342
>>>
答案 1 :(得分:3)
您可以将其定义为dict,如下所示:
d = {"0:5000": {"range": [0, 5000],
"value": 1234},
"5001:10000":{"range":[5001, 10000],
"value": 1432}}
但我认为课程更合适
class MyRange(object):
def __init__(self, start, end, value):
self.start = start
self.end = end
self.value = value
def has_in_range(self, num):
return self.start <= num <= self.end
然后,您可以获得MyRange元素列表
l = [MyRange(0, 5000, 1234), MyRange(5001, 10000, 3124)]
最后,当您想要搜索时,请使用其他功能
def search(num):
for element in l:
if element.has_in_range(num):
return element.value
return -1
以便搜索返回:
>>> search(10)
1234
>>> search(6000)
3124
答案 2 :(得分:2)
一个完全不同(但很快)的选项是使用bisect模块并简单地添加起点和值(假设你的范围是连续的)。
import bisect
ranges = (
(0, 1234),
(5001, 1231),
(10001, 3242),
(50001, 3543),
(100001, 2303),
)
def find_range(value):
min_ = ranges[0][0]
if min_ > value:
raise ValueError('Values smaller than %d are not supported' % min_)
# Search for the insert point using bisect but add 1 so we handle
# corner cases correctly
key = value + 1, 0
# Use bisect to find the index
index = bisect.bisect(ranges, key)
# Return the 2nd item from the tuple since that contains the ID
start_index, id_ = ranges[index - 1]
return id_
print 'Testing standard ranges'
for i in range(15):
i = 2 ** i
print 'Looking for %d, got: %d' % (i, find_range(i))
print
print 'Testing corner cases:'
for start, id_ in ranges:
for i in range(start - 1, start + 2):
try:
value = find_range(i)
except ValueError, value:
pass
print 'Looking for %d, got: %s' % (i, value)
结果:
Testing standard ranges
Looking for 1, got: 1234
Looking for 2, got: 1234
Looking for 4, got: 1234
Looking for 8, got: 1234
Looking for 16, got: 1234
Looking for 32, got: 1234
Looking for 64, got: 1234
Looking for 128, got: 1234
Looking for 256, got: 1234
Looking for 512, got: 1234
Looking for 1024, got: 1234
Looking for 2048, got: 1234
Looking for 4096, got: 1234
Looking for 8192, got: 1231
Looking for 16384, got: 3242
Testing corner cases:
Looking for -1, got: Values smaller than 0 are not supported
Looking for 0, got: 1234
Looking for 1, got: 1234
Looking for 5000, got: 1234
Looking for 5001, got: 1231
Looking for 5002, got: 1231
Looking for 10000, got: 1231
Looking for 10001, got: 3242
Looking for 10002, got: 3242
Looking for 50000, got: 3242
Looking for 50001, got: 3543
Looking for 50002, got: 3543
Looking for 100000, got: 3543
Looking for 100001, got: 2303
Looking for 100002, got: 2303
答案 3 :(得分:1)
我可以假设存储的范围不会在它们之间留下空隙吗?
我会:
答案 4 :(得分:1)
在Python 3.4中,您可以使用范围作为键。但是因为你使用的是2.7,所以这不是一个选择。但对于其他读者来说,也许值得考虑。
d = {
range(0, 5000): 1234,
range(5001, 10000): 1231,
range(10001, 20000): 3242
}
x = 6000
r = [i[1] for i in d.items() if x in i[0]][0]
# r == 1231
您可以对此进行改进,以了解x
不在任何范围内的情况。
答案 5 :(得分:0)
这是Wolph的竞争对手,使用他的代码,但改变了:
import bisect
range_stops = [0, 4, 8]
range_ids = [0, 1, 2]
def find_range(value):
# Need to limit to `0` because there is no -1th index
index = max(0, bisect.bisect_right(range_stops, value)-1)
return range_ids[index]
for i in range(-2, 10):
print("{:2} → {}".format(i, find_range(i)))
#>>> -2 → 0
#>>> -1 → 0
#>>> 0 → 0
#>>> 1 → 0
#>>> 2 → 0
#>>> 3 → 0
#>>> 4 → 1
#>>> 5 → 1
#>>> 6 → 1
#>>> 7 → 1
#>>> 8 → 2
#>>> 9 → 2
这稍微简单一些,但需要两个数据结构而不是一个。从好的方面来说,工作要容易得多。它还将支持浮点范围和索引。