bisect_left による最近傍探索

一言まとめ

bisect_left が返すのは挿入位置であって最近傍ではない。最近傍は返り値 i の左右 i-1 と i を両方比べて決める。

作成 · 更新 · #python#bisect#algorithm

bisect_left(a, x) が返すのは「ソート順を保ったまま x を挿入できる位置」であって、x に最も近い要素の位置ではありません。返り値を i とすると、a[i] は x 以上で最小の要素、a[i-1] は x 未満で最大の要素です。最近傍はこのどちらかなので、両方見ないと取り逃します。

from bisect import bisect_left
def nearest(a, x):
"""a はソート済み。x に最も近い要素を返す。"""
i = bisect_left(a, x)
cands = []
if i < len(a):
cands.append(a[i])
if i > 0:
cands.append(a[i - 1])
return min(cands, key=lambda v: abs(v - x))

端のガードが要ります。x が全要素より大きいと i == len(a) になって a[i] が IndexError、全要素より小さいと i == 0 で a[i-1] が末尾を指してしまいます。後者はエラーにならず誤った値を返すので、こちらの方が厄介です。

元ネタは AtCoder ABC212 C(Min Difference)で、片方をソートしてもう片方の各要素で最近傍を引く形です。

更新履歴#

  • 2026-06-21: 初版(memos から移行)
  • 2026-10-09: タイトルを概念名に揃え、tags を補う

同じトピック — Python