ferray_ma/filled.rs
1// ferray-ma: filled and compressed (REQ-5, REQ-6)
2
3use ferray_core::Array;
4use ferray_core::dimension::{Dimension, Ix1};
5use ferray_core::dtype::Element;
6use ferray_core::error::FerrayResult;
7
8use crate::MaskedArray;
9
10impl<T, D> MaskedArray<T, D>
11where
12 T: Element + Copy,
13 D: Dimension,
14{
15 /// Return a regular array with masked positions replaced by `fill_value`.
16 ///
17 /// Unmasked positions retain their original data values.
18 ///
19 /// # Errors
20 /// Returns an error only for internal failures.
21 pub fn filled(&self, fill_value: T) -> FerrayResult<Array<T, D>> {
22 let data: Vec<T> = self
23 .data()
24 .iter()
25 .zip(self.mask().iter())
26 .map(|(v, m)| if *m { fill_value } else { *v })
27 .collect();
28 Array::from_vec(self.dim().clone(), data)
29 }
30
31 /// Return a regular array with masked positions replaced by the array's
32 /// stored [`MaskedArray::fill_value`].
33 ///
34 /// Equivalent to `NumPy`'s `arr.filled()` with no argument. Use [`MaskedArray::filled`]
35 /// to override the fill value for a single call.
36 ///
37 /// # Errors
38 /// Returns an error only for internal failures.
39 pub fn filled_default(&self) -> FerrayResult<Array<T, D>> {
40 self.filled(self.fill_value)
41 }
42
43 /// Return a 1-D array containing only the unmasked elements.
44 ///
45 /// The order is the logical (row-major) iteration order of the
46 /// original array, with masked elements removed.
47 ///
48 /// # Errors
49 /// Returns an error only for internal failures.
50 pub fn compressed(&self) -> FerrayResult<Array<T, Ix1>> {
51 let data: Vec<T> = self
52 .data()
53 .iter()
54 .zip(self.mask().iter())
55 .filter(|(_, m)| !**m)
56 .map(|(v, _)| *v)
57 .collect();
58 let len = data.len();
59 Array::from_vec(Ix1::new([len]), data)
60 }
61}