我知道我可以将奇异值作为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。算法本身用于作业,但具体实现只是为了改善生成实验数据的运行时间。
答案 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)
欢迎进一步的编辑和改进! 特里的方法涉及更多,在我看来,它更适合低级语言。