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(&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.cast_with_options(
26            &DataType::Decimal(None, Some(scale as usize)),
27            CastOptions::NonStrict,
28        )
29    }
30}
31
32#[cfg(test)]
33mod test {
34    #[test]
35    fn test_inferred_length() {
36        use super::*;
37        let vals = [
38            "1.0",
39            "invalid",
40            "225.0",
41            "3.00045",
42            "-4.0",
43            "5.104",
44            "5.25251525353",
45        ];
46        let s = StringChunked::from_slice(PlSmallStr::from_str("test"), &vals);
47        let s = s.to_decimal(6).unwrap();
48        assert_eq!(s.dtype(), &DataType::Decimal(None, Some(5)));
49        assert_eq!(s.len(), 7);
50        assert_eq!(s.get(0).unwrap(), AnyValue::Decimal(100000, 5));
51        assert_eq!(s.get(1).unwrap(), AnyValue::Null);
52        assert_eq!(s.get(3).unwrap(), AnyValue::Decimal(300045, 5));
53        assert_eq!(s.get(4).unwrap(), AnyValue::Decimal(-400000, 5));
54        assert_eq!(s.get(6).unwrap(), AnyValue::Decimal(525251, 5));
55    }
56}