polars_core/chunked_array/ops/
decimal.rs

1use crate::chunked_array::cast::CastOptions;
2use crate::prelude::*;
3
4impl StringChunked {
5    /// Convert an [`StringChunked`] to a [`Series`] of [`DataType::Decimal`].
6    /// Scale needed for the decimal type are inferred.  Parsing is not strict.  
7    /// Scale inference assumes that all tested strings are well-formed numbers,
8    /// and may produce unexpected results for scale if this is not the case.
9    ///
10    /// If the decimal `precision` and `scale` are already known, consider
11    /// using the `cast` method.
12    pub fn to_decimal_infer(&self, infer_length: usize) -> PolarsResult<Series> {
13        let mut scale = 0;
14        let mut iter = self.into_iter();
15        let mut valid_count = 0;
16        while let Some(Some(v)) = iter.next() {
17            let scale_value = arrow::compute::decimal::infer_scale(v.as_bytes());
18            scale = std::cmp::max(scale, scale_value);
19            valid_count += 1;
20            if valid_count == infer_length {
21                break;
22            }
23        }
24
25        self.to_decimal(scale as usize)
26    }
27
28    pub fn to_decimal(&self, scale: usize) -> PolarsResult<Series> {
29        self.cast_with_options(
30            &DataType::Decimal(None, Some(scale)),
31            CastOptions::NonStrict,
32        )
33    }
34}
35
36#[cfg(test)]
37mod test {
38    #[test]
39    fn test_inferred_length() {
40        use super::*;
41        let vals = [
42            "1.0",
43            "invalid",
44            "225.0",
45            "3.00045",
46            "-4.0",
47            "5.104",
48            "5.25251525353",
49        ];
50        let s = StringChunked::from_slice(PlSmallStr::from_str("test"), &vals);
51        let s = s.to_decimal_infer(6).unwrap();
52        assert_eq!(s.dtype(), &DataType::Decimal(None, Some(5)));
53        assert_eq!(s.len(), 7);
54        assert_eq!(s.get(0).unwrap(), AnyValue::Decimal(100000, 5));
55        assert_eq!(s.get(1).unwrap(), AnyValue::Null);
56        assert_eq!(s.get(3).unwrap(), AnyValue::Decimal(300045, 5));
57        assert_eq!(s.get(4).unwrap(), AnyValue::Decimal(-400000, 5));
58        assert_eq!(s.get(6).unwrap(), AnyValue::Decimal(525251, 5));
59    }
60}