1717
1818//! Defines windowing functions, like `shift`ing
1919
20- use crate :: { array:: new_null_array, compute:: concat} ;
21- use num:: { abs, clamp} ;
22-
2320use crate :: array:: { Array , ArrayRef } ;
2421use crate :: { array:: PrimitiveArray , datatypes:: ArrowPrimitiveType , error:: Result } ;
22+ use crate :: {
23+ array:: { make_array, new_null_array} ,
24+ compute:: concat,
25+ } ;
26+ use num:: { abs, clamp} ;
2527
2628/// Shifts array by defined number of items (to left or right)
2729/// A positive value for `offset` shifts the array to the right
@@ -33,56 +35,120 @@ use crate::{array::PrimitiveArray, datatypes::ArrowPrimitiveType, error::Result}
3335/// use arrow::compute::shift;
3436///
3537/// let a: Int32Array = vec![Some(1), None, Some(4)].into();
38+ ///
3639/// // shift array 1 element to the right
3740/// let res = shift(&a, 1).unwrap();
3841/// let expected: Int32Array = vec![None, Some(1), None].into();
39- /// assert_eq!(res.as_ref(), &expected)
42+ /// assert_eq!(res.as_ref(), &expected);
43+ ///
44+ /// // shift array 1 element to the left
45+ /// let res = shift(&a, -1).unwrap();
46+ /// let expected: Int32Array = vec![None, Some(4), None].into();
47+ /// assert_eq!(res.as_ref(), &expected);
48+ ///
49+ /// // shift array 0 element, although not recommended
50+ /// let res = shift(&a, 0).unwrap();
51+ /// let expected: Int32Array = vec![Some(1), None, Some(4)].into();
52+ /// assert_eq!(res.as_ref(), &expected);
53+ ///
54+ /// // shift array 3 element tot he right
55+ /// let res = shift(&a, 3).unwrap();
56+ /// let expected: Int32Array = vec![None, None, None].into();
57+ /// assert_eq!(res.as_ref(), &expected);
4058/// ```
4159pub fn shift < T > ( values : & PrimitiveArray < T > , offset : i64 ) -> Result < ArrayRef >
4260where
4361 T : ArrowPrimitiveType ,
4462{
45- // Compute slice
46- let slice_offset = clamp ( -offset, 0 , values. len ( ) as i64 ) as usize ;
47- let length = values. len ( ) - abs ( offset) as usize ;
48- let slice = values. slice ( slice_offset, length) ;
49-
50- // Generate array with remaining `null` items
51- let nulls = abs ( offset as i64 ) as usize ;
63+ let value_len = values. len ( ) as i64 ;
64+ if offset == 0 {
65+ Ok ( make_array ( values. data_ref ( ) . clone ( ) ) )
66+ } else if offset == i64:: MIN || abs ( offset) >= value_len {
67+ Ok ( new_null_array ( & T :: DATA_TYPE , values. len ( ) ) )
68+ } else {
69+ let slice_offset = clamp ( -offset, 0 , value_len) as usize ;
70+ let length = values. len ( ) - abs ( offset) as usize ;
71+ let slice = values. slice ( slice_offset, length) ;
5272
53- let null_arr = new_null_array ( & T :: DATA_TYPE , nulls) ;
73+ // Generate array with remaining `null` items
74+ let nulls = abs ( offset) as usize ;
75+ let null_arr = new_null_array ( & T :: DATA_TYPE , nulls) ;
5476
55- // Concatenate both arrays, add nulls after if shift > 0 else before
56- if offset > 0 {
57- concat ( & [ null_arr. as_ref ( ) , slice. as_ref ( ) ] )
58- } else {
59- concat ( & [ slice. as_ref ( ) , null_arr. as_ref ( ) ] )
77+ // Concatenate both arrays, add nulls after if shift > 0 else before
78+ if offset > 0 {
79+ concat ( & [ null_arr. as_ref ( ) , slice. as_ref ( ) ] )
80+ } else {
81+ concat ( & [ slice. as_ref ( ) , null_arr. as_ref ( ) ] )
82+ }
6083 }
6184}
6285
6386#[ cfg( test) ]
6487mod tests {
65- use crate :: array:: Int32Array ;
66-
6788 use super :: * ;
89+ use crate :: array:: Int32Array ;
6890
6991 #[ test]
7092 fn test_shift_neg ( ) {
7193 let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
7294 let res = shift ( & a, -1 ) . unwrap ( ) ;
73-
7495 let expected: Int32Array = vec ! [ None , Some ( 4 ) , None ] . into ( ) ;
75-
7696 assert_eq ! ( res. as_ref( ) , & expected) ;
7797 }
7898
7999 #[ test]
80100 fn test_shift_pos ( ) {
81101 let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
82102 let res = shift ( & a, 1 ) . unwrap ( ) ;
83-
84103 let expected: Int32Array = vec ! [ None , Some ( 1 ) , None ] . into ( ) ;
104+ assert_eq ! ( res. as_ref( ) , & expected) ;
105+ }
106+
107+ #[ test]
108+ fn test_shift_nil ( ) {
109+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
110+ let res = shift ( & a, 0 ) . unwrap ( ) ;
111+ let expected: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
112+ assert_eq ! ( res. as_ref( ) , & expected) ;
113+ }
85114
115+ #[ test]
116+ fn test_shift_boundary_pos ( ) {
117+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
118+ let res = shift ( & a, 3 ) . unwrap ( ) ;
119+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
120+ assert_eq ! ( res. as_ref( ) , & expected) ;
121+ }
122+
123+ #[ test]
124+ fn test_shift_boundary_neg ( ) {
125+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
126+ let res = shift ( & a, -3 ) . unwrap ( ) ;
127+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
128+ assert_eq ! ( res. as_ref( ) , & expected) ;
129+ }
130+
131+ #[ test]
132+ fn test_shift_boundary_neg_min ( ) {
133+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
134+ let res = shift ( & a, i64:: MIN ) . unwrap ( ) ;
135+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
136+ assert_eq ! ( res. as_ref( ) , & expected) ;
137+ }
138+
139+ #[ test]
140+ fn test_shift_large_pos ( ) {
141+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
142+ let res = shift ( & a, 1000 ) . unwrap ( ) ;
143+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
144+ assert_eq ! ( res. as_ref( ) , & expected) ;
145+ }
146+
147+ #[ test]
148+ fn test_shift_large_neg ( ) {
149+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
150+ let res = shift ( & a, -1000 ) . unwrap ( ) ;
151+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
86152 assert_eq ! ( res. as_ref( ) , & expected) ;
87153 }
88154}
0 commit comments