|
28 | 28 | NDArrayMixin,
|
29 | 29 | either_dict_or_kwargs,
|
30 | 30 | get_valid_numpy_dtype,
|
| 31 | + is_scalar, |
31 | 32 | to_0d_array,
|
32 | 33 | )
|
33 | 34 |
|
@@ -840,20 +841,32 @@ def decompose_indexer(
|
840 | 841 | raise TypeError(f"unexpected key type: {indexer}")
|
841 | 842 |
|
842 | 843 |
|
843 |
| -def _decompose_slice(key, size): |
| 844 | +def _decompose_slice(key: slice, size: int) -> tuple[slice, slice]: |
844 | 845 | """convert a slice to successive two slices. The first slice always has
|
845 | 846 | a positive step.
|
| 847 | +
|
| 848 | + >>> _decompose_slice(slice(2, 98, 2), 99) |
| 849 | + (slice(2, 98, 2), slice(None, None, None)) |
| 850 | +
|
| 851 | + >>> _decompose_slice(slice(98, 2, -2), 99) |
| 852 | + (slice(4, 99, 2), slice(None, None, -1)) |
| 853 | +
|
| 854 | + >>> _decompose_slice(slice(98, 2, -2), 98) |
| 855 | + (slice(3, 98, 2), slice(None, None, -1)) |
| 856 | +
|
| 857 | + >>> _decompose_slice(slice(360, None, -10), 361) |
| 858 | + (slice(0, 361, 10), slice(None, None, -1)) |
846 | 859 | """
|
847 | 860 | start, stop, step = key.indices(size)
|
848 | 861 | if step > 0:
|
849 | 862 | # If key already has a positive step, use it as is in the backend
|
850 | 863 | return key, slice(None)
|
851 | 864 | else:
|
852 | 865 | # determine stop precisely for step > 1 case
|
| 866 | + # Use the range object to do the calculation |
853 | 867 | # e.g. [98:2:-2] -> [98:3:-2]
|
854 |
| - stop = start + int((stop - start - 1) / step) * step + 1 |
855 |
| - start, stop = stop + 1, start + 1 |
856 |
| - return slice(start, stop, -step), slice(None, None, -1) |
| 868 | + exact_stop = range(start, stop, step)[-1] |
| 869 | + return slice(exact_stop, start + 1, -step), slice(None, None, -1) |
857 | 870 |
|
858 | 871 |
|
859 | 872 | def _decompose_vectorized_indexer(
|
@@ -979,12 +992,25 @@ def _decompose_outer_indexer(
|
979 | 992 | [14, 15, 14],
|
980 | 993 | [ 8, 9, 8]])
|
981 | 994 | """
|
982 |
| - if indexing_support == IndexingSupport.VECTORIZED: |
983 |
| - return indexer, BasicIndexer(()) |
| 995 | + backend_indexer: list[Any] = [] |
| 996 | + np_indexer: list[Any] = [] |
| 997 | + |
984 | 998 | assert isinstance(indexer, (OuterIndexer, BasicIndexer))
|
985 | 999 |
|
986 |
| - backend_indexer: list[Any] = [] |
987 |
| - np_indexer = [] |
| 1000 | + if indexing_support == IndexingSupport.VECTORIZED: |
| 1001 | + for k, s in zip(indexer.tuple, shape): |
| 1002 | + if isinstance(k, slice): |
| 1003 | + # If it is a slice, then we will slice it as-is |
| 1004 | + # (but make its step positive) in the backend, |
| 1005 | + bk_slice, np_slice = _decompose_slice(k, s) |
| 1006 | + backend_indexer.append(bk_slice) |
| 1007 | + np_indexer.append(np_slice) |
| 1008 | + else: |
| 1009 | + backend_indexer.append(k) |
| 1010 | + if not is_scalar(k): |
| 1011 | + np_indexer.append(slice(None)) |
| 1012 | + return type(indexer)(tuple(backend_indexer)), BasicIndexer(tuple(np_indexer)) |
| 1013 | + |
988 | 1014 | # make indexer positive
|
989 | 1015 | pos_indexer: list[np.ndarray | int | np.number] = []
|
990 | 1016 | for k, s in zip(indexer.tuple, shape):
|
|
0 commit comments