From 00a48217e93bea1e84f10dbfdf3c0c93dfe1ea3d Mon Sep 17 00:00:00 2001 From: LucasG0 <44552904+LucasG0@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:38:28 +0100 Subject: [PATCH] GH-38768: [Python] Slicing an array backwards beyond the start now includes first item. (#39240) ### What changes are included in this PR? Minor changes in `_normalize_slice` so `start` and `stop` are both computed in a single if/else block instead of having them modified later in case of a negative `step`. ### Are these changes tested? Yes. ### Are there any user-facing changes? Fixing wrong data returned in an edge case. * Closes: #38768 Authored-by: LucasG0 Signed-off-by: Joris Van den Bossche --- python/pyarrow/array.pxi | 40 ++++++++++++++++-------------- python/pyarrow/tests/test_array.py | 1 + 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/python/pyarrow/array.pxi b/python/pyarrow/array.pxi index 7d9b65c77d25a..def4c5e9ba962 100644 --- a/python/pyarrow/array.pxi +++ b/python/pyarrow/array.pxi @@ -549,32 +549,36 @@ def _normalize_slice(object arrow_obj, slice key): Py_ssize_t start, stop, step Py_ssize_t n = len(arrow_obj) - start = key.start or 0 - if start < 0: - start += n + step = key.step or 1 + + if key.start is None: + if step < 0: + start = n - 1 + else: + start = 0 + elif key.start < 0: + start = key.start + n if start < 0: start = 0 - elif start >= n: + elif key.start >= n: start = n + else: + start = key.start - stop = key.stop if key.stop is not None else n - if stop < 0: - stop += n - if stop < 0: + if step < 0 and (key.stop is None or key.stop < -n): + stop = -1 + elif key.stop is None: + stop = n + elif key.stop < 0: + stop = key.stop + n + if stop < 0: # step > 0 in this case. stop = 0 - elif stop >= n: + elif key.stop >= n: stop = n + else: + stop = key.stop - step = key.step or 1 if step != 1: - if step < 0: - # Negative steps require some special handling - if key.start is None: - start = n - 1 - - if key.stop is None: - stop = -1 - indices = np.arange(start, stop, step) return arrow_obj.take(indices) else: diff --git a/python/pyarrow/tests/test_array.py b/python/pyarrow/tests/test_array.py index 782c41d0d7015..a8cd20720e437 100644 --- a/python/pyarrow/tests/test_array.py +++ b/python/pyarrow/tests/test_array.py @@ -485,6 +485,7 @@ def test_array_slice_negative_step(): slice(10, 2, -2), slice(None, None, 2), slice(0, 10, 2), + slice(15, -25, -1), # GH-38768 ] for case in cases: