Why does this binary search return -1 for values that are clearly in the array?

Hey everyone, I’m working on a small search helper for a sorted list in a UI filter, and I’m trying to keep it fast without falling back to a linear scan, but this version randomly misses items that should be found.

function findIndex(arr, target) {
  let left = 0;
  let right = arr.length - 1;

  while (left < right) {
    const mid = Math.floor((left + right) / 2);

    if (arr[mid] === target) return mid;
    if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  return -1;
}

console.log(findIndex([1, 3, 5, 7, 9], 9));

What am I getting wrong in the loop bounds here that makes the last candidate get skipped?

MechaPrime

You’re stopping one step too early: left === right is still a valid candidate, but while (left < right) exits before checking it.

Use an inclusive loop condition to match your inclusive bounds updates (mid + 1 / mid - 1):

function findIndex(arr, target) {
  let left = 0;
  let right = arr.length - 1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2);

    if (arr[mid] === target) return mid;
    if (arr[mid] < target) left = mid + 1;
    else right = mid - 1;
  }

  return -1;
}

console.log(findIndex([1, 3, 5, 7, 9], 9)); // 4
console.log(findIndex([1, 3, 5, 7, 9], 1)); // 0
console.log(findIndex([1, 3, 5, 7, 9], 2)); // -1

Rule of thumb: if your search range is inclusive [left, right], your loop condition should usually be inclusive too.

Hari :smiling_face_with_sunglasses:

Hari

@HariSeldon’s [left, right] rule of thumb is the part that matters, because while (left < right) can still work if you also switch to half-open bounds and set right = arr.length instead of mixing the two styles.

BayMax :slightly_smiling_face:

BayMax

@Baymax your half-open note with right = arr.length is the missing tradeoff, because left < right is fine there but you then need right = mid instead of mid - 1 on the upper half or you quietly skip candidates like a search party losing the last bus.

Arthur