在Python中使用范围作为字典索引

Using a range as a dictionary index in Python

本问题已经有最佳答案,请猛点这里访问。

是否可以做如下的事情:

1
2
3
4
5
r = {range(0, 100): 'foo', range(100, 200): 'bar'}

print r[42]

> 'foo'

所以我想使用一个数字范围作为字典索引的一部分。为了使事情更复杂,我还想使用多个索引,如('a', range(0,100))。所以这个概念在理想情况下应该可以扩展到这一点。有什么建议吗?

这里也提出了类似的问题,但我对全面的实施感兴趣,而不是对该问题的不同方法感兴趣。


如果您在python 3.x上,可以使用range对象作为键,但要检索值,您需要执行以下操作:

1
2
3
4
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__方法。


作为一种替代方法,如果您试图查找与特定范围相关的值,可以使用内置的python bisect库,如下所示:

1
2
3
4
5
6
7
import bisect

def boundaries(num, breakpoints=[100, 200], result=['foo', 'bar']):
    i = bisect.bisect(breakpoints, num-1)
    return result[i]

print boundaries(42)

这将显示:

1
foo


如果您有一种简单的方法从一个点计算范围,例如,如果所有范围都是固定大小,则可以使用:

1
2
3
def getIndex(p):
   start = floor(p/100)*100
   return (start, start+100)

然后定义听写:

1
r = {(0, 100): 'foo', (100, 200): 'bar'}

和访问:

10

该方法的有效性如下:

  • 您没有为范围内的每个数字保留dict中的项目(这也允许您拥有真正的值"keys")。
  • 您不需要通过整个dict来查找值,得到的值是o(1)
  • 另外,您的getIndex函数可能更复杂,例如,如果您的范围在长度上不规则,您的getIndex函数可以二进制搜索范围边界的排序列表并返回范围元组,不再是O(1),但O(log(n))也不错……


    只能将不可变的数据类型用作键。所以没有列表。

    但可以使用元组定义上界和下界。

    1
    r = {(0,100): 'foo', (100,200): 'bar'}

    我可以这样得到42的值:

    1
    2
    3
    4
    5
    res =""
    for (k1,k2) in r:
        if (k1 < 42 and k2 > 42):
             res = r[(k1,k2)]
    print(res)

    但我承认你不需要字典。


    您可以使用列表理解获得所需的字典:

    1
    2
    d = dict([(i,'foo') for i in range(0, 100)] + [(i,'bar') for i in range(100, 200)])
    print d

    你可以排成一行

    1
    r = dict(zip(range(200),["foo"]*100+["bar"]*100))


    你可以用这个:

    1
    2
    3
    r=dict(zip(range(100),["foo"]*100))
    r2=dict(zip(range(100,200),["bar"]*100))
    r.update(r2)