@@ -523,71 +523,71 @@ def test_get_indexer_non_unique_right(self):
523523 tm .assert_index_equal (result , expected )
524524
525525
526- class TestGetIndexerMonotonic :
527- """Tests for the searchsorted-based fast path in _get_indexer for
528- monotonic non-overlapping IntervalIndex with scalar targets (GH#47614)."" "
529-
530- def test_get_indexer_scalars_all_closed ( self , closed ):
531- # GH#47614 - boundary behavior for each closed value
532- # Use gaps between all intervals to avoid overlap with closed="both"
533- tuples = [( 0 , 1 ), ( 2 , 3 ), ( 5 , 6 ) ]
534- index = IntervalIndex . from_tuples ( tuples , closed = closed )
535-
536- # Points to test: before, on boundaries, interior, in gaps, after
537- query = [ - 0.5 , 0 , 0.5 , 1 , 1.5 , 2 , 2.5 , 3 , 4 , 5 , 5.5 , 6 , 6.5 ]
538-
539- closed_left = closed in ( "left" , "both" )
540- closed_right = closed in ( "right" , "both" )
541-
542- expected = []
543- for val in query :
544- found = - 1
545- for idx , ( left , right ) in enumerate ( tuples ):
546- in_left = val > left if not closed_left else val >= left
547- in_right = val < right if not closed_right else val <= right
548- if in_left and in_right :
549- found = idx
550- break
551- expected . append ( found )
552-
553- result = index . get_indexer ( query )
554- tm . assert_numpy_array_equal ( result , np . array ( expected , dtype = "intp" ))
555-
556- def test_get_indexer_with_nans_in_target ( self , closed ):
557- # GH#47614 - NaN in scalar target should return -1
558- index = IntervalIndex . from_tuples ([( 0 , 1 ), ( 2 , 3 )], closed = closed )
559- result = index . get_indexer ([ 0.5 , np . nan , 2.5 ])
560- expected = np . array ([ 0 , - 1 , 1 ], dtype = "intp" )
561- tm . assert_numpy_array_equal ( result , expected )
562-
563- def test_get_indexer_non_monotonic_with_scalars ( self ):
564- # GH#47614 - non-monotonic falls back to IntervalTree
565- index = IntervalIndex . from_tuples ([( 2 , 3 ), ( 0 , 1 )] )
566- result = index . get_indexer ([ 0.5 , 2.5 , 1.5 ] )
567- expected = np . array ([ 1 , 0 , - 1 ], dtype = "intp" )
568- tm . assert_numpy_array_equal ( result , expected )
569-
570- def test_get_indexer_monotonic_datetime ( self ):
571- # GH#47614 - datetime IntervalIndex with scalar targets
572- breaks = date_range ( "2018-01-01" , periods = 4 , unit = "ns" )
573- index = IntervalIndex . from_breaks ( breaks )
574- # 2018-01-01T12 :00 -> interval 0, 2018-01-05 -> past end,
575- # 2018-01-02T12:00 -> interval 1
576- target = DatetimeIndex (
577- [ "2018-01-01T12:00" , "2018-01-05" , "2018-01-02T12:00" ], dtype = "M8[ns]"
578- )
579- result = index . get_indexer ( target )
580- expected = np . array ([ 0 , - 1 , 1 ], dtype = "intp" )
581- tm . assert_numpy_array_equal ( result , expected )
582-
583- def test_get_indexer_monotonic_timedelta ( self ):
584- # GH#47614 - timedelta IntervalIndex with scalar targets
585- breaks = timedelta_range ("0 days" , periods = 4 )
586- index = IntervalIndex .from_breaks (breaks )
587- target = Index ([Timedelta ("0.5 days" ), Timedelta ("3.5 days" )])
588- result = index .get_indexer (target )
589- expected = np .array ([0 , - 1 ], dtype = "intp" )
590- tm .assert_numpy_array_equal (result , expected )
526+ def test_get_indexer_scalars_all_closed ( closed ) :
527+ # GH#47614 - boundary behavior for each closed value
528+ # Use gaps between all intervals to avoid overlap with closed="both "
529+ tuples = [( 0 , 1 ), ( 2 , 3 ), ( 5 , 6 )]
530+ index = IntervalIndex . from_tuples ( tuples , closed = closed )
531+
532+ # Points to test: before, on boundaries, interior, in gaps, after
533+ query = [- 0.5 , 0 , 0.5 , 1 , 1.5 , 2 , 2.5 , 3 , 4 , 5 , 5.5 , 6 , 6.5 ]
534+
535+ closed_left = closed in ( "left" , "both" )
536+ closed_right = closed in ( "right" , "both" )
537+
538+ expected = []
539+ for val in query :
540+ found = - 1
541+ for idx , ( left , right ) in enumerate ( tuples ):
542+ in_left = val > left if not closed_left else val >= left
543+ in_right = val < right if not closed_right else val <= right
544+ if in_left and in_right :
545+ found = idx
546+ break
547+ expected . append ( found )
548+
549+ result = index . get_indexer ( query )
550+ tm . assert_numpy_array_equal ( result , np . array ( expected , dtype = "intp" ))
551+
552+
553+ def test_get_indexer_with_nans_in_target ( closed ):
554+ # GH#47614 - NaN in scalar target should return -1
555+ index = IntervalIndex . from_tuples ([( 0 , 1 ), ( 2 , 3 )], closed = closed )
556+ result = index . get_indexer ([ 0.5 , np . nan , 2.5 ])
557+ expected = np . array ([ 0 , - 1 , 1 ], dtype = "intp" )
558+ tm . assert_numpy_array_equal ( result , expected )
559+
560+
561+ def test_get_indexer_non_monotonic_with_scalars ():
562+ # GH#47614 - non-monotonic falls back to IntervalTree
563+ index = IntervalIndex . from_tuples ([( 2 , 3 ), ( 0 , 1 )])
564+ result = index . get_indexer ([ 0.5 , 2.5 , 1.5 ])
565+ expected = np . array ([ 1 , 0 , - 1 ], dtype = "intp" )
566+ tm . assert_numpy_array_equal ( result , expected )
567+
568+
569+ def test_get_indexer_scalar_monotonic_datetime ():
570+ # GH#47614 - datetime IntervalIndex with scalar targets
571+ breaks = date_range ( "2018-01-01" , periods = 4 , unit = "ns" )
572+ index = IntervalIndex . from_breaks ( breaks )
573+ # 2018-01-01T12:00 -> interval 0, 2018-01-05 -> past end,
574+ # 2018-01-02T12 :00 -> interval 1
575+ target = DatetimeIndex (
576+ [ "2018-01-01T12:00" , "2018-01-05" , "2018-01-02T12:00" ], dtype = "M8[ns]"
577+ )
578+ result = index . get_indexer ( target )
579+ expected = np . array ([ 0 , - 1 , 1 ], dtype = "intp" )
580+ tm . assert_numpy_array_equal ( result , expected )
581+
582+
583+ def test_get_indexer_scalar_monotonic_timedelta ( ):
584+ # GH#47614 - timedelta IntervalIndex with scalar targets
585+ breaks = timedelta_range ("0 days" , periods = 4 )
586+ index = IntervalIndex .from_breaks (breaks )
587+ target = Index ([Timedelta ("0.5 days" ), Timedelta ("3.5 days" )])
588+ result = index .get_indexer (target )
589+ expected = np .array ([0 , - 1 ], dtype = "intp" )
590+ tm .assert_numpy_array_equal (result , expected )
591591
592592
593593class TestSliceLocs :
0 commit comments