@@ -745,39 +745,50 @@ def _time_shift(self, periods, freq=None):
745
745
result .name = self .name
746
746
return result
747
747
748
- def _intersect_ascending (self , other ):
749
- # to make our life easier, "sort" the two ranges
750
- if self [0 ] <= other [0 ]:
751
- left , right = self , other
752
- else :
753
- left , right = other , self
754
-
755
- end = min (left [- 1 ], right [- 1 ])
756
- start = right [0 ]
748
+ def _fast_intersection (self , other ):
749
+ """
750
+ Speedy intersection that works only if certain assumptions are met.
751
+ See intersection for details.
752
+ Parameters
753
+ ----------
754
+ other
757
755
758
- if end < start :
759
- return []
760
- return left .values [slice (* left .slice_locs (start , end ))]
756
+ Returns
757
+ -------
761
758
762
- def _intersect_descending (self , other ):
763
- # this is essentially a flip of _intersect_ascending
764
- if self [0 ] >= other [0 ]:
759
+ """
760
+ # Coerce into the same order
761
+ ascending = self .is_monotonic_increasing
762
+ if ascending != other .is_monotonic_increasing :
763
+ other = other .sort_values (ascending = ascending )
764
+ # Lots of 'if ascending' calls here to setup mirrored function calls
765
+ first_comparison = '__le__' if ascending else '__ge__'
766
+ second_comparison = '__lt__' if ascending else '__gt__'
767
+ if getattr (self [0 ], first_comparison )(other [0 ]):
765
768
left , right = self , other
766
769
else :
767
770
left , right = other , self
768
771
769
- start = min (left [0 ], right [0 ])
770
- end = right [- 1 ]
771
-
772
- if end > start :
773
- return Index ()
774
- return left .values [slice (* left .slice_locs (start , end ))]
772
+ if ascending :
773
+ start = right [0 ]
774
+ end = min (left [- 1 ], right [- 1 ])
775
+ else :
776
+ start = min (left [0 ], right [0 ])
777
+ end = right [- 1 ]
778
+ if getattr (end , second_comparison , start ):
779
+ return left .values [slice (* left .slice_locs (start , end ))]
780
+ return []
775
781
776
782
def intersection (self , other ):
777
783
"""
778
784
Specialized intersection for DateTimeIndexOpsMixin objects.
779
785
May be much faster than Index.intersection.
780
786
787
+ Fast intersection will occur if
788
+ 1. Both are in a sorted order
789
+ 2. Both indexes have a `freq` , and it's the same `freq`
790
+ 3. Both are monotonic
791
+
781
792
Parameters
782
793
----------
783
794
other : Index or array-like
@@ -787,6 +798,9 @@ def intersection(self, other):
787
798
Index
788
799
A shallow copied intersection between the two things passed in
789
800
"""
801
+ # Run a few checks, and perform a regular intersection
802
+ # if the conditions aren't just right for fast intersection
803
+ # Perform a regular Index.intersection
790
804
self ._assert_can_do_setop (other )
791
805
792
806
if self .equals (other ):
@@ -798,12 +812,9 @@ def intersection(self, other):
798
812
if lengths [1 ] == 0 :
799
813
return other
800
814
801
- if not isinstance (other , Index ):
802
- result = Index .intersection (self , other )
803
- return result
804
- elif (index_offsets_equal (self , other ) or
805
- (not self ._is_strictly_monotonic or
806
- not other ._is_strictly_monotonic )):
815
+ if (not index_offsets_equal (self , other ) or
816
+ (not self ._is_strictly_monotonic or
817
+ not other ._is_strictly_monotonic )):
807
818
result = Index .intersection (self , other )
808
819
result = self ._shallow_copy (result ._values , name = result .name ,
809
820
tz = getattr (self , 'tz' , None ),
@@ -813,23 +824,8 @@ def intersection(self, other):
813
824
result .offset = frequencies .to_offset (result .inferred_freq )
814
825
return result
815
826
816
- # handle intersecting things like this
817
- # idx1 = pd.to_timedelta((1, 2, 3, 4, 5, 6, 7, 8), unit='s')
818
- # idx2 = pd.to_timedelta((2, 3, 4, 8), unit='s')
819
- if lengths [0 ] != lengths [1 ] and (
820
- max (self ) != max (other ) or min (self ) != min (other )):
821
- return Index .intersection (self , other )
822
-
823
- # coerce into same order
824
- self_ascending = self .is_monotonic_increasing
825
- if self_ascending != other .is_monotonic_increasing :
826
- other = other .sort_values (ascending = self_ascending )
827
-
828
- if self_ascending :
829
- intersected_slice = self ._intersect_ascending (other )
830
- else :
831
- intersected_slice = self ._intersect_descending (other )
832
-
827
+ # Conditions met!
828
+ intersected_slice = self ._fast_intersection (other )
833
829
intersected = self ._shallow_copy (intersected_slice )
834
830
return intersected ._get_consensus_name (other )
835
831
0 commit comments