@@ -154,6 +154,41 @@ where
154154 A : Ord + Clone ,
155155 S : DataMut ;
156156
157+ /// Equally spaces `sample` indexes around the center of `array` and sorts them by their values.
158+ ///
159+ /// `sample` content is ignored but its length defines the sample size and sample space divider.
160+ ///
161+ /// **Panics** if `self.len() < sample.len() + 2`.
162+ ///
163+ /// ```
164+ /// use ndarray::Array1;
165+ /// use ndarray_stats::Sort1dExt;
166+ /// use noisy_float::types::n64;
167+ ///
168+ /// // Define sample size of 5.
169+ /// let mut sample = [0; 5];
170+ ///
171+ /// // Create array from 99 down to 0;
172+ /// let mut array = Array1::range(n64(100.0), n64(0.0), n64(-1.0));
173+ /// assert_eq!(array.len(), 100);
174+ ///
175+ /// // Find `sample` indices and sort their values `array[sample[s]]`.
176+ /// array.sample_mut(&mut sample);
177+ ///
178+ /// // Equally spaced by 13 non-sample elements around center of 50.
179+ /// let assert = [22, 36, 50, 64, 78];
180+ /// assert_eq!(sample, &assert[..]);
181+ /// // Ensure `array[sample[s]]` is sorted.
182+ /// assert_eq!(sample.map(|s| array[s]), assert.map(|s| s as f64));
183+ /// // Ensure reverse order of non-sample elements is preserved.
184+ /// assert_eq!(array[49], n64(51.0));
185+ /// assert_eq!(array[51], n64(49.0));
186+ /// ```
187+ fn sample_mut ( & mut self , sample : & mut [ usize ] )
188+ where
189+ A : Ord + Clone ,
190+ S : DataMut ;
191+
157192 private_decl ! { }
158193}
159194
@@ -179,7 +214,7 @@ where
179214 } else {
180215 // Sorted sample of 5 equally spaced elements around the center.
181216 let mut sample = [ 0 ; 5 ] ;
182- sample_mut ( self , & mut sample) ;
217+ self . sample_mut ( & mut sample) ;
183218 // Adapt pivot sampling to relative sought rank and switch from dual-pivot to
184219 // single-pivot partitioning for extreme sought ranks.
185220 let sought_rank = i as f64 / n as f64 ;
@@ -344,6 +379,29 @@ where
344379 ( lower, upper)
345380 }
346381
382+ fn sample_mut ( & mut self , sample : & mut [ usize ] )
383+ where
384+ A : Ord + Clone ,
385+ S : DataMut ,
386+ {
387+ // Assumes arrays of at least `sample.len() + 2` elements.
388+ assert ! ( self . len( ) >= sample. len( ) + 2 ) ;
389+ // Space between sample indexes.
390+ let space = self . len ( ) / ( sample. len ( ) + 2 ) ;
391+ // Lowermost sample index.
392+ let lowermost = self . len ( ) / 2 - ( sample. len ( ) / 2 ) * space;
393+ // Equally space sample indexes and sort them by their values by looking up their indexes.
394+ for mut index in 0 ..sample. len ( ) {
395+ // Equally space sample indexes based on their lowermost index.
396+ sample[ index] = lowermost + index * space;
397+ // Insertion sort looking up only the already equally spaced sample indexes.
398+ while index > 0 && self [ sample[ index - 1 ] ] > self [ sample[ index] ] {
399+ self . swap ( sample[ index - 1 ] , sample[ index] ) ;
400+ index -= 1 ;
401+ }
402+ }
403+ }
404+
347405 private_impl ! { }
348406}
349407
@@ -423,7 +481,7 @@ fn _get_many_from_sorted_mut_unchecked<A>(
423481
424482 // Sorted sample of 5 equally spaced elements around the center.
425483 let mut sample = [ 0 ; 5 ] ;
426- sample_mut ( & mut array , & mut sample) ;
484+ array . sample_mut ( & mut sample) ;
427485 // Since there is no single sought rank to adapt pivot sampling to, the recommended skewed
428486 // pivot sampling of dual-pivot Quicksort is used in the assumption that multiple indexes
429487 // change characteristics from Quickselect towards Quicksort.
@@ -505,29 +563,3 @@ fn _get_many_from_sorted_mut_unchecked<A>(
505563 ) ;
506564 } ) ;
507565}
508-
509- /// Equally space `sample` indexes around the center of `array` and sort them by their values.
510- ///
511- /// `sample` content is ignored but its length defines the sample size and the sample space divider.
512- ///
513- /// Assumes arrays of at least `sample.len() + 2` elements.
514- pub ( crate ) fn sample_mut < A , S > ( array : & mut ArrayBase < S , Ix1 > , sample : & mut [ usize ] )
515- where
516- A : Ord + Clone ,
517- S : DataMut < Elem = A > ,
518- {
519- // Space between sample indexes.
520- let space = array. len ( ) / ( sample. len ( ) + 2 ) ;
521- // Lowermost sample index.
522- let lowermost = array. len ( ) / 2 - ( sample. len ( ) / 2 ) * space;
523- // Equally space sample indexes and sort them by their values by looking up their indexes.
524- for mut index in 0 ..sample. len ( ) {
525- // Equally space sample indexes based on their lowermost index.
526- sample[ index] = lowermost + index * space;
527- // Insertion sort looking up only the already equally spaced sample indexes.
528- while index > 0 && array[ sample[ index - 1 ] ] > array[ sample[ index] ] {
529- array. swap ( sample[ index - 1 ] , sample[ index] ) ;
530- index -= 1 ;
531- }
532- }
533- }
0 commit comments