From efa5c595598a94cc534cd917b39875e81f99f4b6 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Tue, 11 May 2021 11:18:20 -0400 Subject: [PATCH] Replace hand-rolled binary search with bisect_left (#50410) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `bisect` module exposes a `bisect_left` function which does basically what the bulk of `_lower_bound` does. From my tests, it is slightly faster (~5%) in the probably common ideal case where `arr` is short. In the worst case scenario, `bisect.bisect_left` is *much* faster. ``` >>> arr = list(range(60)) >>> cmp = 59 >>> %timeit _lower_bound(arr, cmp) 736 ns ± 6.24 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) >>> %timeit bisect_lower_bound(arr, cmp) 290 ns ± 7.77 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) ``` I doubt this is a huge bottleneck or anything, but I think it's a bit more readable, and it's more efficient, so it seems like it's mostly a win. This commit *will* add a new unconditional import for `bisect` when importing `util.dt`, and `bisect` is not currently imported for any of the standard library modules. It is possible to make this conditional by placing `import bisect` in the _lower_bound function, or in the function it's nested in. --- homeassistant/util/dt.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/homeassistant/util/dt.py b/homeassistant/util/dt.py index c818c955370..28aebc5db47 100644 --- a/homeassistant/util/dt.py +++ b/homeassistant/util/dt.py @@ -1,6 +1,7 @@ """Helper methods to handle the time in Home Assistant.""" from __future__ import annotations +import bisect from contextlib import suppress import datetime as dt import re @@ -265,15 +266,7 @@ def find_next_time_expression_time( Return None if no such value exists. """ - left = 0 - right = len(arr) - while left < right: - mid = (left + right) // 2 - if arr[mid] < cmp: - left = mid + 1 - else: - right = mid - + left = bisect.bisect_left(arr, cmp) if left == len(arr): return None return arr[left]