散列一系列价值观

时间:2012-01-28 05:28:06

标签: python hash universal-hashing

我知道我可以将奇异值作为dict中的键。例如,我可以将5哈希作为dict中的一个键。

我目前面临一个问题,需要我散列一系列值。

基本上,我需要一种更快的方法来实现这一目标:

if 0 <= x <= 0.1:
    # f(A)
elif 0.1 <= x <= 0.2:
    # f(B)
elif 0.2 <= x <= 0.3:
    # f(C)
elif 0.3 <= x <= 0.4:
    # f(D)
elif 0.4 <= x <= 0.5:
    # f(E)
elif 0.5 <= x <= 0.6:
    # f(F)

其中x是任意精度的float参数。

我能想到的最快的方法是散列,但问题在于:我可以使用(0.1, 0.2)作为键,但这仍然会花费我O(n)运行时间并最终不会比大约elif s(我必须迭代键并检查是否key[0] <= x <= key[1])。

有没有办法对一系列值进行散列,以便我可以检查0.15的哈希表并仍然获得#execute B

如果无法进行此类散列,我还能如何改善其运行时间?我正在使用足够大的数据集,线性运行时不够快。

编辑:在回答cheeken的回答时,我必须注意,不能认为这些间隔是正常的。事实上,我几乎可以保证他们不是

在回应评论中的请求时,我应该提到我这样做是为了实现fitness-based selection in a genetic algorithm。算法本身用于作业,但具体实现只是为了改善生成实验数据的运行时间。

4 个答案:

答案 0 :(得分:11)

正如其他人所指出的那样,你要获得的最好的算法就是O(log N),而不是O(1),其中包含通过排序列表进行二分搜索的内容。

在Python中执行此操作的最简单方法是使用bisect标准模块http://docs.python.org/library/bisect.html。请注意,特别是8.5.2节中的示例,在进行数字表查找时 - 它正是您正在做的事情:

>>> def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
...     i = bisect(breakpoints, score)
...     return grades[i]
...
>>> [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
['F', 'A', 'C', 'C', 'B', 'A', 'A']

grades字符串替换为函数列表,将breakpoints列表替换为较低阈值列表,然后就可以了。

答案 1 :(得分:4)

您不一定需要散列整个值范围。例如,在上面给出的比例中,如果给出0.15,则可以将其四舍五入为0.2(小数点后的第一个数字),然后反转为0.2。

这有多高效?您可以尝试的另一种方法是二进制搜索。让间隔值按列表中的排序顺序存储,并对其进行二进制搜索。例如:

sorted_list = [ (0.1, function1), (0.2, function2), ....(0.6, function6) ] 

然后你只需进行二分查找就可以找到大于x的最小元素。这将产生O(log(n))。

答案 2 :(得分:3)

如果您的间隔是常规的,您可以缩放,然后将floor操作数调整到每个范围的最小值,然后将该结果直接传递到dict映射到相应处理程序的下限。 / p>

使用您提供的范围的示例实现。

# Integerize our 0.1 width intervals; scale by x10
handlerDict = {}
handlerDict[0] = lambda x: ... # 0.1
handlerDict[1] = lambda x: ... # 0.2
handlerDict[2] = lambda x: ... # 0.3
...

# Get the right handler, scaling x by x10; handle
handlerDict[int(10*x)](x, ...)

答案 3 :(得分:3)

为了改善运行时,您可以实现二分搜索。

否则,您可以将间隔阈值放在trie上。

编辑: 让我提出一个实施:

class IntervalHash():
    def __init__(self,SortedList):
        #check it's sorted 
        self.MyList = []
        self.MyList.extend(SortedList) 
        self.lenlist = len(self.MyList)
    def get_interval(self,a):
        mylen = self.lenlist 
        mypos = 0
        while mylen > 1:
            mylen = (mylen/2 + mylen % 2)
            if mypos + mylen > self.lenlist - 1:
                if self.MyList[self.lenlist - 1] < a:
                    mypos = self.lenlist - 1
                break
            if self.MyList[mypos + mylen] < a:
                mypos += mylen
        if mypos == 0:
            if self.MyList[0] > a: 
                return ("-infty",self.MyList[0],0)
        if mypos == self.lenlist - 1:
            return (self.MyList[mypos],"infty",0)
        return (self.MyList[mypos],self.MyList[mypos+1],0)

A = [0.32,0.70,1.13]
MyHasher = IntervalHash(A)
print "Intervals are:",A
print 0.9 ," is in ",MyHasher.get_interval(0.9)
print 0.1 ," is in ",MyHasher.get_interval(0.1)
print 1.8 ," is in ",MyHasher.get_interval(1.8)

欢迎进一步的编辑和改进! 特里的方法涉及更多,在我看来,它更适合低级语言。