1- use crate :: BinaryNumber ;
1+ use crate :: { BinaryNumber , PositionsError } ;
22use is_sorted:: IsSorted ;
3+ use itertools:: Itertools ;
34use std:: collections:: HashMap ;
45use std:: fmt;
56use std:: ops:: { Add , Deref } ;
@@ -194,6 +195,34 @@ impl<'a> SparseBinSlice<'a> {
194195}
195196
196197impl < T : Deref < Target = [ usize ] > > SparseBinVecBase < T > {
198+ /// Creates a new vector with the given length and list of non trivial positions
199+ /// or returns as error if the positions are unsorted, greater or equal to length
200+ /// or contain duplicates.
201+ ///
202+ ///
203+ /// # Example
204+ ///
205+ /// ```
206+ /// # use sparse_bin_mat::SparseBinVec;
207+ /// use sparse_bin_mat::PositionsError;
208+ ///
209+ /// let vector = SparseBinVec::try_new(5, vec![0, 2]);
210+ /// assert_eq!(vector, Ok(SparseBinVec::new(5, vec![0, 2])));
211+ ///
212+ /// let vector = SparseBinVec::try_new(5, vec![2, 0]);
213+ /// assert_eq!(vector, Err(PositionsError::Unsorted));
214+ ///
215+ /// let vector = SparseBinVec::try_new(5, vec![0, 10]);
216+ /// assert_eq!(vector, Err(PositionsError::OutOfBound));
217+ ///
218+ /// let vector = SparseBinVec::try_new(5, vec![0, 0]);
219+ /// assert_eq!(vector, Err(PositionsError::Duplicated));
220+ /// ```
221+ pub fn try_new ( length : usize , positions : T ) -> Result < Self , PositionsError > {
222+ validate_positions ( length, & positions) ?;
223+ Ok ( Self { positions, length } )
224+ }
225+
197226 /// Returns the length (number of elements) of the vector.
198227 pub fn len ( & self ) -> usize {
199228 self . length
@@ -317,7 +346,8 @@ impl<T: Deref<Target = [usize]>> SparseBinVecBase<T> {
317346 SparseBinVec :: new ( self . len ( ) + other. len ( ) , positions)
318347 }
319348
320- /// Returns a new vector keeping only the given positions.
349+ /// Returns a new vector keeping only the given positions or an error
350+ /// if the positions are unsorted, out of bound or contain deplicate.
321351 ///
322352 /// Positions are relabeled to the fit new number of positions.
323353 ///
@@ -328,23 +358,11 @@ impl<T: Deref<Target = [usize]>> SparseBinVecBase<T> {
328358 /// let vector = SparseBinVec::new(5, vec![0, 2, 4]);
329359 /// let truncated = SparseBinVec::new(3, vec![0, 2]);
330360 ///
331- /// assert_eq!(vector.keep_only_positions(&[0, 1, 2]), truncated);
332- /// assert_eq!(vector.keep_only_positions(&[1, 2]).len(), 2 );
361+ /// assert_eq!(vector.keep_only_positions(&[0, 1, 2]), Ok( truncated) );
362+ /// assert_eq!(vector.keep_only_positions(&[1, 2]).map(|vec| vec. len()), Ok(2) );
333363 /// ```
334- ///
335- /// # Panic
336- ///
337- /// Panics if some positions are out of bound.
338- pub fn keep_only_positions ( & self , positions : & [ usize ] ) -> SparseBinVec {
339- for position in positions {
340- if * position >= self . len ( ) {
341- panic ! (
342- "position {} is out of bound for length {}" ,
343- position,
344- self . len( )
345- ) ;
346- }
347- }
364+ pub fn keep_only_positions ( & self , positions : & [ usize ] ) -> Result < SparseBinVec , PositionsError > {
365+ validate_positions ( self . length , positions) ?;
348366 let old_to_new_positions_map = positions
349367 . iter ( )
350368 . enumerate ( )
@@ -354,10 +372,11 @@ impl<T: Deref<Target = [usize]>> SparseBinVecBase<T> {
354372 . non_trivial_positions ( )
355373 . filter_map ( |position| old_to_new_positions_map. get ( & position) . cloned ( ) )
356374 . collect ( ) ;
357- SparseBinVec :: new ( positions. len ( ) , new_positions)
375+ Ok ( SparseBinVec :: new ( positions. len ( ) , new_positions) )
358376 }
359377
360- /// Returns a truncated vector where the given positions are removed.
378+ /// Returns a truncated vector where the given positions are remove or an error
379+ /// if the positions are unsorted or out of bound.
361380 ///
362381 /// Positions are relabeled to fit the new number of positions.
363382 ///
@@ -368,14 +387,10 @@ impl<T: Deref<Target = [usize]>> SparseBinVecBase<T> {
368387 /// let vector = SparseBinVec::new(5, vec![0, 2, 4]);
369388 /// let truncated = SparseBinVec::new(3, vec![0, 2]);
370389 ///
371- /// assert_eq!(vector.without_positions(&[3, 4]), truncated);
372- /// assert_eq!(vector.without_positions(&[1, 2]).len(), 3 );
390+ /// assert_eq!(vector.without_positions(&[3, 4]), Ok( truncated) );
391+ /// assert_eq!(vector.without_positions(&[1, 2]).map(|vec| vec. len()), Ok(3) );
373392 /// ```
374- ///
375- /// # Panic
376- ///
377- /// Panics if some positions are out of bound.
378- pub fn without_positions ( & self , positions : & [ usize ] ) -> SparseBinVec {
393+ pub fn without_positions ( & self , positions : & [ usize ] ) -> Result < SparseBinVec , PositionsError > {
379394 let to_keep: Vec < usize > = ( 0 ..self . len ( ) ) . filter ( |x| !positions. contains ( x) ) . collect ( ) ;
380395 self . keep_only_positions ( & to_keep)
381396 }
@@ -457,6 +472,21 @@ impl<T: Deref<Target = [usize]>> fmt::Display for SparseBinVecBase<T> {
457472 }
458473}
459474
475+ fn validate_positions ( length : usize , positions : & [ usize ] ) -> Result < ( ) , PositionsError > {
476+ for position in positions. iter ( ) {
477+ if * position >= length {
478+ return Result :: Err ( PositionsError :: OutOfBound ) ;
479+ }
480+ }
481+ if !IsSorted :: is_sorted ( & mut positions. iter ( ) ) {
482+ return Result :: Err ( PositionsError :: Unsorted ) ;
483+ }
484+ if positions. iter ( ) . unique ( ) . count ( ) != positions. len ( ) {
485+ return Result :: Err ( PositionsError :: Duplicated ) ;
486+ }
487+ Ok ( ( ) )
488+ }
489+
460490#[ cfg( test) ]
461491mod test {
462492 use super :: * ;
0 commit comments