This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: help(bisect.bisect_left)
Type: behavior Stage: resolved
Components: Versions: Python 3.11
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: PeterChu, mallika.bachan, miss-islington, rhettinger
Priority: normal Keywords: patch

Created on 2021-05-25 01:07 by mallika.bachan, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 26340 closed mallika.bachan, 2021-05-25 02:06
PR 26548 merged PeterChu, 2021-06-06 08:24
PR 26563 merged miss-islington, 2021-06-06 18:24
Messages (5)
msg394280 - (view) Author: Mallika Bachan (mallika.bachan) * Date: 2021-05-25 01:07
Documentation issue.

help(bisect.bisect_left)
says: "... if x already appears in the list, i points just before the leftmost x already there."
but in fact, it actually points *to* the leftmost x already there
msg394283 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-05-25 01:29
I there is a misunderstanding here.  The bisect functions never point *to* a value.  Instead, they are documented to return "insertion points".  Those always occur just before or after a specific value:

values:              10   20   30   30   30   40   50
insertion points:   |   |    |    |    |    |    |    |
                    0   1    2    3    4    5    6    7
bisect_left(30) -------------^
bisect_right(30) ---------------------------^

As you can see, bisect_left() does in fact point JUST BEFORE the 30.

Note this is also how slicing works.  Here's an example:

    >>> from bisect import bisect_left, bisect_right
    >>> s = [10, 20, 30, 30, 30, 40, 50]
    >>> i = bisect_left(s, 30)
    >>> j = bisect_right(s, 30)
    >>> s[i : j]
    [30, 30, 30]
msg394294 - (view) Author: Mallika Bachan (mallika.bachan) * Date: 2021-05-25 04:36
Conceptually, yes, but the function does return an index, and values are
stored at these indices. The index it returns holds the leftmost occurrence
of the target (should the target exist)
>>> bisect.bisect_left([1,2,2,3],2)
1
If we insert at this index, it will push the current value right, so
conceptually, sure, it can help to think of the insertion point as being
just before the leftmost target value.

But while bisect_right does in fact return value i that "points just beyond
the rightmost x already there" ("just beyond" gets interpreted as "the next
one", because only whole indices are used), making the statement "i points
just before the leftmost x already there" for the return value of
bisect_left definitely appears incorrect.

On Mon, May 24, 2021 at 6:30 PM Raymond Hettinger <report@bugs.python.org>
wrote:

>
> Raymond Hettinger <raymond.hettinger@gmail.com> added the comment:
>
> I there is a misunderstanding here.  The bisect functions never point *to*
> a value.  Instead, they are documented to return "insertion points".  Those
> always occur just before or after a specific value:
>
> values:              10   20   30   30   30   40   50
> insertion points:   |   |    |    |    |    |    |    |
>                     0   1    2    3    4    5    6    7
> bisect_left(30) -------------^
> bisect_right(30) ---------------------------^
>
> As you can see, bisect_left() does in fact point JUST BEFORE the 30.
>
> Note this is also how slicing works.  Here's an example:
>
>     >>> from bisect import bisect_left, bisect_right
>     >>> s = [10, 20, 30, 30, 30, 40, 50]
>     >>> i = bisect_left(s, 30)
>     >>> j = bisect_right(s, 30)
>     >>> s[i : j]
>     [30, 30, 30]
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <https://bugs.python.org/issue44227>
> _______________________________________
>
msg394822 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-05-31 19:03
> Conceptually, yes, but the function does return an index,

The function does not return an index.  It returns an integer that represents an insertion point.  The documentation is clear about this:

    Locate the insertion point for x in a to maintain sorted order.
    ...
    return value is suitable for use as the first
    parameter to list.insert()

Likewise, the documented and precise invariants are stated in terms of slice points:

   The returned insertion point i partitions the array ``a ``
   into two halves so that ``all(val < x for val in a[lo : i])``
   for the left side and ``all(val >= x for val in a[i : hi])``
   for the right side.


> and values are stored at these indices.

That isn't true:

    >>> bisect([], 5)
    0

There is no value at 0.

The bisect functions are all about insertion points and ranges.  They aren't expressed in terms of an index and value.  The underlying algorithm never checks for equality.  Instead, it only uses __lt__(), so it is never aware of having "found" a value at all.

For people with use cases expressed in terms of index and value, there is a separate section of the docs showing show how to bridge between what they want and what the module actually does:

    https://docs.python.org/3.10/library/bisect.html#searching-sorted-lists
msg395211 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-06-06 19:53
New changeset b5cedd098043dc58ecf9c2f33774cd7646506a92 by Miss Islington (bot) in branch '3.10':
bpo-44227: Update bisect docstrings (GH-26548) (GH-26563)
https://github.com/python/cpython/commit/b5cedd098043dc58ecf9c2f33774cd7646506a92
History
Date User Action Args
2022-04-11 14:59:46adminsetgithub: 88393
2021-06-06 19:53:02rhettingersetmessages: + msg395211
2021-06-06 18:24:13miss-islingtonsetnosy: + miss-islington

pull_requests: + pull_request25152
2021-06-06 08:24:45PeterChusetnosy: + PeterChu

pull_requests: + pull_request25146
2021-05-31 19:03:54rhettingersetmessages: + msg394822
2021-05-25 04:36:44mallika.bachansetmessages: + msg394294
2021-05-25 03:16:16rhettingersetstatus: open -> closed
resolution: not a bug
stage: patch review -> resolved
2021-05-25 02:06:52mallika.bachansetkeywords: + patch
stage: patch review
pull_requests: + pull_request24933
2021-05-25 01:29:52rhettingersetmessages: + msg394283
2021-05-25 01:11:54rhettingersetassignee: rhettinger

nosy: + rhettinger
2021-05-25 01:07:38mallika.bachancreate