Python中的“模糊”哈希表取代了elif链?

时间:2014-05-25 16:58:03

标签: python-3.x hashmap simplify

选择多个执行路径之一或依赖于变量的数据位的Pythonic方法是使用哈希表,如下所示:

mapping = {'bar':"xyzzy", 'foo':"plugh", 'baz':"frobnitz"}
magic = mapping[command]

如果我想根据值是否在多个值范围之一中选择执行路径,我该怎么办?

或者,更简洁地说,我如何对此进行pythonicize:

    #A value from one to four indicates an O-type star. 4/58 chance.
    if typeselec <= 4:
        self.specttype="O"
    #A value from 5-20 indicates a B-type star. 15/58 chance.
    elif typeselec <= 20:
        self.specttype="B"
    #A value from 20-30 indicates an A-type star. 10/58 chance.
    elif typeselec <= 30:
        self.specttype="A"
    #A value from 31-36 indicates an F-type star. 6/58 chance.
    elif typeselec <= 36:
        self.specttype="F"
    #A value from 37-40 indicates a G-type star. 4/58 chance.
    elif typeselec <= 40:
        self.specttype="G"
    #A value from 41-50 indicates a K-type star. 10/58 chance.
    elif typeselec <= 22:
        self.specttype="K"
    #A value from 50-58 indicates an M-type star. 8/58 chance.
    else:
        self.specttype="M"

一个明显的方法是{1:'O', 2:'O',3:'O',4:'O',5:'B',6:'B'...},但这看起来非常不优雅和效率低下。还有其他办法吗?

3 个答案:

答案 0 :(得分:3)

正是这种类型或问题被用作bisect模块的示例。

适应您的问题,它看起来像这样:

from bisect import bisect_left

def select_type(typeselec,
                breakpoints=[4, 20, 30, 36, 40, 50],
                types='0BAFGKM'):
    return types[bisect_left(breakpoints, typeselec)]


for i in range(59):
    print(i, select_type(i))

与doc的示例的不同之处在于,断点是下界(<=)的一部分,其中在示例中它是上部的一部分(>= ),因此需要使用bisect_left代替bisectbisect_right的别名)。

Altough bisect的时间复杂度不是O(1),它使用二进制搜索,因此它的时间复杂度为O(log(n)),对于较大的n } O(n)级联的if将是一个很好的改进。

答案 1 :(得分:2)

将您的specttype存储在加权列表中,并以typeselec作为索引进行查找。生成列表后,查找为O(1)。

letters = 'OBAFGKM'
frequencies = (4, 15, 10, 6, 4, 10, 8)

specttypes = []
for i in range(len(letters)):
    l = letters[i]
    f = frequencies[i]
    specttypes = specttypes + [l] * f

self.specttype = specttypes[typeselec-1] # Subtract 1 because of zero indexing.

您可以使用字典而不是单独的可迭代lettersfrequencies,但结果specttypes将按字母顺序排序,除非您使用ordered dictionary

请注意specttypes有57个元素,如上所定义,而不是你提到的58个元素。那是因为你的上一个代码评论自相矛盾;我指定了&#39; M&#39;频率为8而不是9(,指数50-57而不是50-58)。

答案 2 :(得分:0)

如果我们有一大组范围,我会将数字存储在排序的序列中,并使用bisect进行二分搜索;它的O(log(n))用于查找而不是O(n)。仍然不是完美哈希的O(1)。当然,在您展示的非常有限的集合中,您可以将值存储在单个字符串中并将其用作普通查找表。 chikinn的例子是这样做的,但有一个列表(考虑到它,会更高效 - 不需要查找字符串的字符串版本)。