Python: отображение из интервалов в значения

Я рефакторинг функции, которая, учитывая ряд конечных точек, которые неявно определяют интервалы, проверяет, включен ли число в этот интервал, а затем возвращает соответствующий (не связанный каким-либо вычислимым образом). Код, который теперь обрабатывает работу:

if p <= 100: return 0 elif p > 100 and p <= 300: return 1 elif p > 300 and p <= 500: return 2 elif p > 500 and p <= 800: return 3 elif p > 800 and p <= 1000: return 4 elif p > 1000: return 5 

Что ИМО довольно ужасно, и не хватает того, что и интервалы, и возвращаемые значения жестко запрограммированы. Конечно, любое использование любой структуры данных возможно.

 import bisect bisect.bisect_left([100,300,500,800,1000], p) 

Вы можете попробовать:

 def check_mapping(p): mapping = [(100, 0), (300, 1), (500, 2)] # Add all your values and returns here for check, value in mapping: if p <= check: return value print check_mapping(12) print check_mapping(101) print check_mapping(303) 

производит:

 0 1 2 

Как всегда в Python, будут лучшие способы сделать это.

Это действительно ужасно. Без требования не иметь никакого жесткого кодирования, это должно было быть написано так:

 if p <= 100: return 0 elif p <= 300: return 1 elif p <= 500: return 2 elif p <= 800: return 3 elif p <= 1000: return 4 else: return 5 

Ниже приведены примеры создания функции поиска, как линейной, так и бинарного поиска, с выполнением требований без жесткого кодирования и нескольких проверок на две таблицы:

 def make_linear_lookup(keys, values): assert sorted(keys) == keys assert len(values) == len(keys) + 1 def f(query): return values[sum(1 for key in keys if query > key)] return f import bisect def make_bisect_lookup(keys, values): assert sorted(keys) == keys assert len(values) == len(keys) + 1 def f(query): return values[bisect.bisect_left(keys, query)] return f 

Попробуйте что-то вроде:

 d = {(None,100): 0, (100,200): 1, ... (1000, None): 5} value = 300 # example value for k,v in d.items(): if (k[0] is None or value > k[0]) and (k[1] is None or value <= k[1]): return v 

Другой путь …

 def which(lst, p): return len([1 for el in lst if p > el]) lst = [100, 300, 500, 800, 1000] which(lst, 2) which(lst, 101) which(lst, 1001) 
 def which_interval(endpoints, number): for n, endpoint in enumerate(endpoints): if number <= endpoint: return n previous = endpoint return n + 1 

Передайте конечные точки в виде списка в endpoints , например:

 which_interval([100, 300, 500, 800, 1000], 5) 

Редактировать:

Вышеупомянутый – линейный поиск. Ответ Гленна Мейнарда будет иметь лучшую производительность, поскольку он использует алгоритм деления пополам.

Interesting Posts