在字典中查找密钥的最快捷方式

时间:2015-11-10 10:29:23

标签: python performance loops dictionary key

我有一个字典,有超过1100万个键(每个值都是一个列表)。每个键是一个唯一的整数。

e.g。

Dict1 = {11:"a",12:"b",22:"c",56:"d"}

然后,另外,我有一个范围列表,例如 [10-20,30-40,50-60]

我想说,对于我的范围列表中的每个范围,如果密钥在范围内,请浏览字典并返回值。

所以它会回来:

10-20: "a","b"

50-60: "d"

我使用的实际代码是:

 for each_key in sorted(dictionary):
                if each_key in range(start,end):
                    print str(dictionary[each_key])

问题在于这种技术非常漫长,因为它通过了所有1100万个密钥并检查它是否在范围内。

有没有办法可以说“跳过所有字典键,直到找到一个高于起始编号的字典”然后“一旦结束数字高于密钥就停止”?基本上只是某种方式可以很快地在一定范围内放大字典部分?

由于

3 个答案:

答案 0 :(得分:2)

只需使用Python的EAFP原则。请求宽恕比允许更容易。

假设所有密钥都有效,如果不是,则捕获错误:

for key in xrange(start, end):
    try:
        print str(dictionary[key])
    except KeyError:
        pass

这只会尝试将每个数字作为一个键,如果有一个KeyError来自一个不存在的键,那么它将继续进行下一次迭代。

请注意,如果您预计会丢失很多密钥,那么首先测试可能会更快:

for key in xrange(start, end):
    if key in dictionary:
        print str(dictionary[key])

请注意,xrangerange的功能略有不同。它将逐个生成值,而不是提前创建整个列表。在for循环中使用它是有用的,在这种情况下没有缺点。

答案 1 :(得分:0)

我对这个问题的想法是先找到正确的密钥。您的解决方案花费太多时间的原因是它使用O(n)算法来查找正确的密钥。如果我们可以实现二进制搜索方法,复杂性将降低到O(log(n)),这有很大帮助。

以下是我的示例代码。它适用于这个例子,但我不能保证它不会得到一些小错误。只需在那里找到想法并实施你的想法。

def binarySearch(alist, target):
    left = 0
    right = len(alist) -1

    if target>alist[-1]:
        return len(alist)

    while left < right:
        m = (left + right) / 2 
        if alist[m] == target:
            return m
        if alist[m] < target:
            left = m+1
        else:
            right = m
    return left



def work(dictionary, start, end):
    keys = sorted(dictionary.keys())

    start_pos = binarySearch(keys, start)
    end_pos = binarySearch(keys, end)


    print [dictionary[keys[pos]] for pos in range(start_pos,end_pos)] 


dictionary = {11:"a",12:"b",22:"c",56:"d"}
work(dictionary, 10, 20)
work(dictionary, 20, 40)
work(dictionary, 10, 60) 

答案 2 :(得分:-1)

此解决方案(使用OrderedDict和过滤器)可以帮助您。

from collections  import OrderedDict
d = {2:3, 10:89, 4:5, 23:0}
od = OrderedDict(sorted(d.items()))

lst=["1-10","11-20","21-30"]
lower_lst=map(int,[i.split("-")[0] for i in lst])
upper_lst=map(int,[i.split("-")[1] for i in lst])

for low,up in zip(lower_lst,upper_lst):
    print "In range {0}-{1}".format(low,up),filter(lambda a:low <= a[0] <= up,od.iteritems())