本问题已经有最佳答案,请猛点这里访问。
是否可以做如下的事情:
r = {range(0, 100): 'foo', range(100, 200): 'bar'}
print r[42]
> 'foo'
所以我想使用一个数字范围作为字典索引的一部分。为了使事情更复杂,我还想使用多个索引,如('a', range(0,100))。所以这个概念在理想情况下应该可以扩展到这一点。有什么建议吗?
这里也提出了类似的问题,但我对全面的实施感兴趣,而不是对该问题的不同方法感兴趣。
范围是固定的吗?比如说,对于某个整数x,都是range(x*100, (x+1)*100)?
@假尘埃:是的,固定范围
考虑到问题的放松,我会给出一个更简单、更有效的答案。
看看这个质量保证。它与:class RangeDictionary(TransformedDict): def __keytransform__(self, key): dk = sorted(self.keys()) return dk[bisect.bisect(dk, key)],然后r = RangeDictionary({100: 'foo', 200: 'bar', 250: 'xyz'}); print(r[42]); print(r[142]); print(r[242])生产foo bar xyz。仅覆盖def __getitem__(self, key): return self.store[self.__keytransform__(key)]。
如果您在python 3.x上,可以使用range对象作为键,但要检索值,您需要执行以下操作:
In [33]: r = {range(0, 100): 'foo', range(100, 200): 'bar'}
In [34]: { r[key] for key in r if 42 in key}
Out[34]: {'foo'}
在python2.x中不能这样做的原因是因为2.7版本以后的range函数返回一个列表,并且列表不能用作字典键,因为它们不提供有效的__hash__方法。
很好,谢谢。现在真的是时候转向Python3了。不幸的是,这个项目是在2.7。
作为一种替代方法,如果您试图查找与特定范围相关的值,可以使用内置的python bisect库,如下所示:
import bisect
def boundaries(num, breakpoints=[100, 200], result=['foo', 'bar']):
i = bisect.bisect(breakpoints, num-1)
return result[i]
print boundaries(42)
这将显示:
foo
如果您有一种简单的方法从一个点计算范围,例如,如果所有范围都是固定大小,则可以使用:
def getIndex(p):
start = floor(p/100)*100
return (start, start+100)
然后定义听写:
r = {(0, 100): 'foo', (100, 200): 'bar'}
和访问:10
该方法的有效性如下:
您没有为范围内的每个数字保留dict中的项目(这也允许您拥有真正的值"keys")。
您不需要通过整个dict来查找值,得到的值是o(1)
另外,您的getIndex函数可能更复杂,例如,如果您的范围在长度上不规则,您的getIndex函数可以二进制搜索范围边界的排序列表并返回范围元组,不再是O(1),但O(log(n))也不错……
只能将不可变的数据类型用作键。所以没有列表。
但可以使用元组定义上界和下界。
r = {(0,100): 'foo', (100,200): 'bar'}
我可以这样得到42的值:
res =""
for (k1,k2) in r:
if (k1 < 42 and k2 > 42):
res = r[(k1,k2)]
print(res)
但我承认你不需要字典。
编辑了我的答案
谢谢-我现在该怎么办?:)
添加到我的答案中
您可以使用列表理解获得所需的字典:
d = dict([(i,'foo') for i in range(0, 100)] + [(i,'bar') for i in range(100, 200)])
print d
你可以排成一行
r = dict(zip(range(200),["foo"]*100+["bar"]*100))
你可以用这个:
r=dict(zip(range(100),["foo"]*100))
r2=dict(zip(range(100,200),["bar"]*100))
r.update(r2)
现在这是正确的方法!我很高兴有人强调。
这是低效的。