Хеши диапазон значений

Я знаю, что я могу использовать сингулярные значения как ключи в dict. Например, я могу hash 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 (мне нужно будет перебирать ключи и проверять, есть ли key[0] <= x <= key[1]).

Есть ли способ хешировать диапазон значений, чтобы я мог проверить хеш-таблицу для 0.15 и все равно получить #execute B?

Если такое хэширование невозможно, как еще я смогу улучшить время выполнения этого? Я работаю с достаточно большими наборами данных, что линейное время выполнения недостаточно быстро.

РЕДАКТИРОВАТЬ. В ответ на ответ на скуку я должен отметить, что интервалы нельзя считать регулярными. На самом деле, я могу почти гарантировать, что они не

В ответ на запросы в комментариях я должен упомянуть, что я делаю это в попытке реализовать выбор на основе фитнеса в генетическом алгоритме, Сам алгоритм предназначен для домашних заданий, но конкретная реализация заключается только в том, чтобы улучшить время выполнения для генерации экспериментальных данных.

Ответ 1

Как отмечали другие, лучшим алгоритмом, который вы собираетесь получить для этого, является то, что 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 с вашим списком нижних порогов, и там вы идете.

Ответ 2

Вам не обязательно хешировать весь диапазон значений. Например, в приведенной выше шкале, если вам дали 0,15, вы можете округлить ее до 0,2 (первая цифра после десятичной точки) и вместо этого вместо хэш 0,2.

Насколько эффективно это должно быть? Альтернативой, которую вы можете попробовать, является двоичный поиск. Сохраняйте значения интервалов в отсортированном порядке в списке и выполняйте на нем двоичный поиск. Например:

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

Затем вы просто выполняете двоичный поиск, чтобы найти наименьший элемент, который больше, чем x. Это даст O (log (n)).

Ответ 3

Если ваши интервалы регулярны, вы можете масштабировать, а затем floor ваши операнды до минимума каждого диапазона, а затем передавать этот результат непосредственно в dict, сопоставляя эти нижние границы с соответствующим обработчиком.

Пример реализации, используя диапазоны, которые вы предоставили.

# 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, ...)

Ответ 4

Чтобы улучшить время выполнения, вы можете реализовать поиск по бисекции.

В противном случае вы можете поместить интервальные пороги в trie.

EDIT: позвольте мне предложить реализацию:

class IntervalHash():
    def __init__(self,SortedList):
        #check it 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)

дальнейшие изменения и улучшения приветствуются! Трой подход гораздо более активен, на мой взгляд, он будет более подходящим для языков низкого уровня.