@@ -491,6 +491,13 @@ def _oindex_get(self, key):
491
491
def _vindex_get (self , key ):
492
492
raise NotImplementedError ("This method should be overridden" )
493
493
494
+ def _check_and_raise_if_non_basic_indexer (self , key ):
495
+ if isinstance (key , (VectorizedIndexer , OuterIndexer )):
496
+ raise TypeError (
497
+ "Vectorized indexing with vectorized or outer indexers is not supported. "
498
+ "Please use .vindex and .oindex properties to index the array."
499
+ )
500
+
494
501
@property
495
502
def oindex (self ):
496
503
return IndexCallable (self ._oindex_get )
@@ -517,7 +524,10 @@ def get_duck_array(self):
517
524
518
525
def __getitem__ (self , key ):
519
526
key = expanded_indexer (key , self .ndim )
520
- result = self .array [self .indexer_cls (key )]
527
+ indexer = self .indexer_cls (key )
528
+
529
+ result = apply_indexer (self .array , indexer )
530
+
521
531
if isinstance (result , ExplicitlyIndexed ):
522
532
return type (self )(result , self .indexer_cls )
523
533
else :
@@ -577,7 +587,13 @@ def shape(self) -> tuple[int, ...]:
577
587
return tuple (shape )
578
588
579
589
def get_duck_array (self ):
580
- array = self .array [self .key ]
590
+ if isinstance (self .array , ExplicitlyIndexedNDArrayMixin ):
591
+ array = apply_indexer (self .array , self .key )
592
+ else :
593
+ # If the array is not an ExplicitlyIndexedNDArrayMixin,
594
+ # it may wrap a BackendArray so use its __getitem__
595
+ array = self .array [self .key ]
596
+
581
597
# self.array[self.key] is now a numpy array when
582
598
# self.array is a BackendArray subclass
583
599
# and self.key is BasicIndexer((slice(None, None, None),))
@@ -594,12 +610,10 @@ def _oindex_get(self, indexer):
594
610
595
611
def _vindex_get (self , indexer ):
596
612
array = LazilyVectorizedIndexedArray (self .array , self .key )
597
- return array [indexer ]
613
+ return array . vindex [indexer ]
598
614
599
615
def __getitem__ (self , indexer ):
600
- if isinstance (indexer , VectorizedIndexer ):
601
- array = LazilyVectorizedIndexedArray (self .array , self .key )
602
- return array [indexer ]
616
+ self ._check_and_raise_if_non_basic_indexer (indexer )
603
617
return type (self )(self .array , self ._updated_key (indexer ))
604
618
605
619
def __setitem__ (self , key , value ):
@@ -643,7 +657,13 @@ def shape(self) -> tuple[int, ...]:
643
657
return np .broadcast (* self .key .tuple ).shape
644
658
645
659
def get_duck_array (self ):
646
- array = self .array [self .key ]
660
+
661
+ if isinstance (self .array , ExplicitlyIndexedNDArrayMixin ):
662
+ array = apply_indexer (self .array , self .key )
663
+ else :
664
+ # If the array is not an ExplicitlyIndexedNDArrayMixin,
665
+ # it may wrap a BackendArray so use its __getitem__
666
+ array = self .array [self .key ]
647
667
# self.array[self.key] is now a numpy array when
648
668
# self.array is a BackendArray subclass
649
669
# and self.key is BasicIndexer((slice(None, None, None),))
@@ -662,6 +682,7 @@ def _vindex_get(self, indexer):
662
682
return type (self )(self .array , self ._updated_key (indexer ))
663
683
664
684
def __getitem__ (self , indexer ):
685
+ self ._check_and_raise_if_non_basic_indexer (indexer )
665
686
# If the indexed array becomes a scalar, return LazilyIndexedArray
666
687
if all (isinstance (ind , integer_types ) for ind in indexer .tuple ):
667
688
key = BasicIndexer (tuple (k [indexer .tuple ] for k in self .key .tuple ))
@@ -706,12 +727,13 @@ def get_duck_array(self):
706
727
return self .array .get_duck_array ()
707
728
708
729
def _oindex_get (self , key ):
709
- return type (self )(_wrap_numpy_scalars (self .array [key ]))
730
+ return type (self )(_wrap_numpy_scalars (self .array . oindex [key ]))
710
731
711
732
def _vindex_get (self , key ):
712
- return type (self )(_wrap_numpy_scalars (self .array [key ]))
733
+ return type (self )(_wrap_numpy_scalars (self .array . vindex [key ]))
713
734
714
735
def __getitem__ (self , key ):
736
+ self ._check_and_raise_if_non_basic_indexer (key )
715
737
return type (self )(_wrap_numpy_scalars (self .array [key ]))
716
738
717
739
def transpose (self , order ):
@@ -745,12 +767,13 @@ def get_duck_array(self):
745
767
return self .array .get_duck_array ()
746
768
747
769
def _oindex_get (self , key ):
748
- return type (self )(_wrap_numpy_scalars (self .array [key ]))
770
+ return type (self )(_wrap_numpy_scalars (self .array . oindex [key ]))
749
771
750
772
def _vindex_get (self , key ):
751
- return type (self )(_wrap_numpy_scalars (self .array [key ]))
773
+ return type (self )(_wrap_numpy_scalars (self .array . vindex [key ]))
752
774
753
775
def __getitem__ (self , key ):
776
+ self ._check_and_raise_if_non_basic_indexer (key )
754
777
return type (self )(_wrap_numpy_scalars (self .array [key ]))
755
778
756
779
def transpose (self , order ):
@@ -912,10 +935,21 @@ def explicit_indexing_adapter(
912
935
result = raw_indexing_method (raw_key .tuple )
913
936
if numpy_indices .tuple :
914
937
# index the loaded np.ndarray
915
- result = NumpyIndexingAdapter (result )[numpy_indices ]
938
+ indexable = NumpyIndexingAdapter (result )
939
+ result = apply_indexer (indexable , numpy_indices )
916
940
return result
917
941
918
942
943
+ def apply_indexer (indexable , indexer ):
944
+ """Apply an indexer to an indexable object."""
945
+ if isinstance (indexer , VectorizedIndexer ):
946
+ return indexable .vindex [indexer ]
947
+ elif isinstance (indexer , OuterIndexer ):
948
+ return indexable .oindex [indexer ]
949
+ else :
950
+ return indexable [indexer ]
951
+
952
+
919
953
def decompose_indexer (
920
954
indexer : ExplicitIndexer , shape : tuple [int , ...], indexing_support : IndexingSupport
921
955
) -> tuple [ExplicitIndexer , ExplicitIndexer ]:
@@ -987,10 +1021,10 @@ def _decompose_vectorized_indexer(
987
1021
>>> array = np.arange(36).reshape(6, 6)
988
1022
>>> backend_indexer = OuterIndexer((np.array([0, 1, 3]), np.array([2, 3])))
989
1023
>>> # load subslice of the array
990
- ... array = NumpyIndexingAdapter(array)[backend_indexer]
1024
+ ... array = NumpyIndexingAdapter(array).oindex [backend_indexer]
991
1025
>>> np_indexer = VectorizedIndexer((np.array([0, 2, 1]), np.array([0, 1, 0])))
992
1026
>>> # vectorized indexing for on-memory np.ndarray.
993
- ... NumpyIndexingAdapter(array)[np_indexer]
1027
+ ... NumpyIndexingAdapter(array).vindex [np_indexer]
994
1028
array([ 2, 21, 8])
995
1029
"""
996
1030
assert isinstance (indexer , VectorizedIndexer )
@@ -1072,7 +1106,7 @@ def _decompose_outer_indexer(
1072
1106
... array = NumpyIndexingAdapter(array)[backend_indexer]
1073
1107
>>> np_indexer = OuterIndexer((np.array([0, 2, 1]), np.array([0, 1, 0])))
1074
1108
>>> # outer indexing for on-memory np.ndarray.
1075
- ... NumpyIndexingAdapter(array)[np_indexer]
1109
+ ... NumpyIndexingAdapter(array).oindex [np_indexer]
1076
1110
array([[ 2, 3, 2],
1077
1111
[14, 15, 14],
1078
1112
[ 8, 9, 8]])
@@ -1395,6 +1429,7 @@ def _vindex_get(self, key):
1395
1429
return array [key .tuple ]
1396
1430
1397
1431
def __getitem__ (self , key ):
1432
+ self ._check_and_raise_if_non_basic_indexer (key )
1398
1433
array , key = self ._indexing_array_and_key (key )
1399
1434
return array [key ]
1400
1435
@@ -1450,15 +1485,8 @@ def _vindex_get(self, key):
1450
1485
raise TypeError ("Vectorized indexing is not supported" )
1451
1486
1452
1487
def __getitem__ (self , key ):
1453
- if isinstance (key , BasicIndexer ):
1454
- return self .array [key .tuple ]
1455
- elif isinstance (key , OuterIndexer ):
1456
- return self .oindex [key ]
1457
- else :
1458
- if isinstance (key , VectorizedIndexer ):
1459
- raise TypeError ("Vectorized indexing is not supported" )
1460
- else :
1461
- raise TypeError (f"Unrecognized indexer: { key } " )
1488
+ self ._check_and_raise_if_non_basic_indexer (key )
1489
+ return self .array [key .tuple ]
1462
1490
1463
1491
def __setitem__ (self , key , value ):
1464
1492
if isinstance (key , (BasicIndexer , OuterIndexer )):
@@ -1499,13 +1527,8 @@ def _vindex_get(self, key):
1499
1527
return self .array .vindex [key .tuple ]
1500
1528
1501
1529
def __getitem__ (self , key ):
1502
- if isinstance (key , BasicIndexer ):
1503
- return self .array [key .tuple ]
1504
- elif isinstance (key , VectorizedIndexer ):
1505
- return self .vindex [key ]
1506
- else :
1507
- assert isinstance (key , OuterIndexer )
1508
- return self .oindex [key ]
1530
+ self ._check_and_raise_if_non_basic_indexer (key )
1531
+ return self .array [key .tuple ]
1509
1532
1510
1533
def __setitem__ (self , key , value ):
1511
1534
if isinstance (key , BasicIndexer ):
@@ -1603,7 +1626,8 @@ def __getitem__(
1603
1626
(key ,) = key
1604
1627
1605
1628
if getattr (key , "ndim" , 0 ) > 1 : # Return np-array if multidimensional
1606
- return NumpyIndexingAdapter (np .asarray (self ))[indexer ]
1629
+ indexable = NumpyIndexingAdapter (np .asarray (self ))
1630
+ return apply_indexer (indexable , indexer )
1607
1631
1608
1632
result = self .array [key ]
1609
1633
0 commit comments