views:

62

answers:

1

I've written the following code to do a binary search for a value, target, in a list or tuple, collection.

def binary(collection, target):
    """Binary search
    Takes a sorted list or tuple, collection, then searches for target
    Returns -1 if item isn't found. """
    length = len(collection)
    minimum = 0
    maximum = length - 1
    while minimum <= maximum:
        pivot = (minimum + maximum) // 2
        if collection[pivot] is target:
            return pivot
        elif collection[pivot] > target:
            minimum = pivot + 1
        else:
            maximum = pivot - 1
    return -1

As you can see, when target isn't found in collection, the function returns -1. No matter what I've done, the function has returned -1.

>>> test = [1, 2, 3, 4, 5, 6]
>>> binary(test, 5)
-1
>>> binary(test, 1)
-1

What's causing this problem?

+4  A: 

You have this condition backwards:

elif collection[pivot] > target:

Switch it and the search works:

elif collection[pivot] < target:

For what it's worth, I figured this out by adding a printout to your search to see what's happening. When in doubt, add a printout:

>>> binary([1, 2, 3], 1)
(min=0, max=2, pivot=1)
(min=2, max=2, pivot=2)
     ^ Oops

# After fixing...
>>> binary([1, 2, 3], 1)
(min=0, max=2, pivot=1)
(min=0, max=0, pivot=0)

By the way, the built-in bisect module performs binary searches. You don't have to write your own, unless you're doing it for educational value.

John Kugelman
Educational value, purely. I sort of banged it out based on what I remembered a binary search to be.
Rafe Kettler
I took a look at the bisect module and it seems that `bisect_left()` can work as a binary search with slight modification. Thanks for the tip.
Rafe Kettler
The last time I tried to write my own binary search it took me around 10 iterations to get the stupid thing working. Off-by-one errors are my kryptonite. :-)
John Kugelman
While we're talking binary search, would it be better to raise a ValueError rather than return -1 if the value isn't found? I feel like if someone used this and didn't read the source or docstring, they'd feed it into a list index and get an index when the value wasn't found (since -1 is a valid index)
Rafe Kettler
Even the Python library can't make up its mind: `str.find` returns -1, `str.index` raises ValueError. Although `list` only has `index`, so maybe that breaks the tie.
John Kugelman
Oh well, doesn't really matter since this isn't production-grade code or anything...
Rafe Kettler