#python
Вопрос:
У меня есть несколько диапазонов даты и времени, связанных со значениями. Я полагаю, что проблема будет такой же для других диапазонов, таких как целые числа.
ranges = [
(datetime.datetime(2021, 6, 10, 10, 0), datetime.datetime(2021, 6, 10, 10, 30), 100),
(datetime.datetime(2021, 6, 10, 10, 30), datetime.datetime(2021, 6, 10, 11, 0), 200),
(datetime.datetime(2021, 6, 10, 11, 0), datetime.datetime(2021, 6, 10, 11, 30), 150),
...
]
Этот список отсортирован и не содержит пробелов или перекрытий. Нижняя граница является всеобъемлющей, а верхняя-исключительной.
Для заданной даты и времени я хотел бы найти значение диапазона, к которому он принадлежит:
def get_value_for_datetime(dt: datetime.datetime) -> int:
???
Например:
>>> get_value_for_datetime(datetime.datetime(2021, 6, 10, 10, 45)
>>> 200
Моей первой мыслью было взглянуть на bisect
модуль, но, похоже, здесь нет ничего, что могло бы помочь мне с диапазонами, и нет способа предоставить пользовательскую функцию для принятия решения смотреть влево или вправо, но, возможно, я что-то упускаю.
Я также не прочь использовать решение numpy и/или pandas, если оно значительно быстрее, а также можно использовать другую структуру для ranges
списка, если это поможет.
Комментарии:
1. Интервалы могут быть любой длины.
Ответ №1:
Вы можете использовать деление пополам на нижних границах, а затем проверить, удовлетворяет ли соответствующая верхняя граница условию upper_bound > value
:
import bisect
lb, ub, values = zip(*ranges)
def get_value_for_datetime(x):
index = bisect.bisect_right(lb, x) - 1
if index == -1 or ub[index] <= x:
raise ValueError(x)
return values[index]