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 } ;
21+ use crate :: { array:: new_null_array, compute:: concat} ;
2422use crate :: { array:: PrimitiveArray , datatypes:: ArrowPrimitiveType , error:: Result } ;
23+ use num:: { abs, clamp} ;
2524
2625/// Shifts array by defined number of items (to left or right)
2726/// A positive value for `offset` shifts the array to the right
@@ -33,56 +32,120 @@ use crate::{array::PrimitiveArray, datatypes::ArrowPrimitiveType, error::Result}
3332/// use arrow::compute::shift;
3433///
3534/// let a: Int32Array = vec![Some(1), None, Some(4)].into();
35+ ///
3636/// // shift array 1 element to the right
3737/// let res = shift(&a, 1).unwrap();
3838/// let expected: Int32Array = vec![None, Some(1), None].into();
39- /// assert_eq!(res.as_ref(), &expected)
39+ /// assert_eq!(res.as_ref(), &expected);
40+ ///
41+ /// // shift array 1 element to the left
42+ /// let res = shift(&a, -1).unwrap();
43+ /// let expected: Int32Array = vec![None, Some(4), None].into();
44+ /// assert_eq!(res.as_ref(), &expected);
45+ ///
46+ /// // shift array 0 element, although not recommended
47+ /// let res = shift(&a, 0).unwrap();
48+ /// let expected: Int32Array = vec![Some(1), None, Some(4)].into();
49+ /// assert_eq!(res.as_ref(), &expected);
50+ ///
51+ /// // shift array 3 element tot he right
52+ /// let res = shift(&a, 3).unwrap();
53+ /// let expected: Int32Array = vec![None, None, None].into();
54+ /// assert_eq!(res.as_ref(), &expected);
4055/// ```
4156pub fn shift < T > ( values : & PrimitiveArray < T > , offset : i64 ) -> Result < ArrayRef >
4257where
4358 T : ArrowPrimitiveType ,
4459{
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 ;
60+ let value_len = values. len ( ) as i64 ;
61+ if offset == 0 {
62+ Ok ( values. slice ( 0 , values. len ( ) ) )
63+ } else if abs ( offset) >= value_len || offset == i64:: MIN {
64+ Ok ( new_null_array ( & T :: DATA_TYPE , values. len ( ) ) )
65+ } else {
66+ let slice_offset = clamp ( -offset, 0 , value_len) as usize ;
67+ let length = values. len ( ) - abs ( offset) as usize ;
68+ let slice = values. slice ( slice_offset, length) ;
5269
53- let null_arr = new_null_array ( & T :: DATA_TYPE , nulls) ;
70+ // Generate array with remaining `null` items
71+ let nulls = abs ( offset) as usize ;
72+ let null_arr = new_null_array ( & T :: DATA_TYPE , nulls) ;
5473
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 ( ) ] )
74+ // Concatenate both arrays, add nulls after if shift > 0 else before
75+ if offset > 0 {
76+ concat ( & [ null_arr. as_ref ( ) , slice. as_ref ( ) ] )
77+ } else {
78+ concat ( & [ slice. as_ref ( ) , null_arr. as_ref ( ) ] )
79+ }
6080 }
6181}
6282
6383#[ cfg( test) ]
6484mod tests {
65- use crate :: array:: Int32Array ;
66-
6785 use super :: * ;
86+ use crate :: array:: Int32Array ;
6887
6988 #[ test]
7089 fn test_shift_neg ( ) {
7190 let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
7291 let res = shift ( & a, -1 ) . unwrap ( ) ;
73-
7492 let expected: Int32Array = vec ! [ None , Some ( 4 ) , None ] . into ( ) ;
75-
7693 assert_eq ! ( res. as_ref( ) , & expected) ;
7794 }
7895
7996 #[ test]
8097 fn test_shift_pos ( ) {
8198 let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
8299 let res = shift ( & a, 1 ) . unwrap ( ) ;
83-
84100 let expected: Int32Array = vec ! [ None , Some ( 1 ) , None ] . into ( ) ;
101+ assert_eq ! ( res. as_ref( ) , & expected) ;
102+ }
85103
104+ #[ test]
105+ fn test_shift_nil ( ) {
106+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
107+ let res = shift ( & a, 0 ) . unwrap ( ) ;
108+ let expected: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
109+ assert_eq ! ( res. as_ref( ) , & expected) ;
110+ }
111+
112+ #[ test]
113+ fn test_shift_boundary_pos ( ) {
114+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
115+ let res = shift ( & a, 3 ) . unwrap ( ) ;
116+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
117+ assert_eq ! ( res. as_ref( ) , & expected) ;
118+ }
119+
120+ #[ test]
121+ fn test_shift_boundary_neg ( ) {
122+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
123+ let res = shift ( & a, -3 ) . unwrap ( ) ;
124+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
125+ assert_eq ! ( res. as_ref( ) , & expected) ;
126+ }
127+
128+ #[ test]
129+ fn test_shift_boundary_neg_min ( ) {
130+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
131+ let res = shift ( & a, i64:: MIN ) . unwrap ( ) ;
132+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
133+ assert_eq ! ( res. as_ref( ) , & expected) ;
134+ }
135+
136+ #[ test]
137+ fn test_shift_large_pos ( ) {
138+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
139+ let res = shift ( & a, 1000 ) . unwrap ( ) ;
140+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
141+ assert_eq ! ( res. as_ref( ) , & expected) ;
142+ }
143+
144+ #[ test]
145+ fn test_shift_large_neg ( ) {
146+ let a: Int32Array = vec ! [ Some ( 1 ) , None , Some ( 4 ) ] . into ( ) ;
147+ let res = shift ( & a, -1000 ) . unwrap ( ) ;
148+ let expected: Int32Array = vec ! [ None , None , None ] . into ( ) ;
86149 assert_eq ! ( res. as_ref( ) , & expected) ;
87150 }
88151}
0 commit comments