polars_core/chunked_array/ops/
decimal.rs1use polars_compute::decimal::dec128_verify_prec_scale;
2
3use crate::chunked_array::cast::CastOptions;
4use crate::prelude::*;
5
6impl StringChunked {
7 pub fn to_decimal_infer(&self, infer_length: usize) -> PolarsResult<Series> {
15 let mut scale = 0;
16 let mut prec = 0;
17 let mut iter = self.into_iter();
18 let mut valid_count = 0;
19 while let Some(Some(v)) = iter.next() {
20 let mut bytes = v.as_bytes();
21 if bytes.first() == Some(&b'-') || bytes.first() == Some(&b'+') {
22 bytes = &bytes[1..];
23 }
24 if let Some(separator) = bytes.iter().position(|b| *b == b'.') {
25 scale = scale.max(bytes.len() - 1 - separator);
26 prec = prec.max(bytes.len() - 1);
27 } else {
28 prec = prec.max(bytes.len());
29 }
30
31 valid_count += 1;
32 if valid_count == infer_length {
33 break;
34 }
35 }
36
37 self.to_decimal(prec, scale)
38 }
39
40 pub fn to_decimal(&self, prec: usize, scale: usize) -> PolarsResult<Series> {
41 dec128_verify_prec_scale(prec, scale)?;
42 self.cast_with_options(&DataType::Decimal(prec, scale), CastOptions::NonStrict)
43 }
44}
45
46#[cfg(test)]
47mod test {
48 #[test]
49 fn test_inferred_length() {
50 use super::*;
51 let vals = [
52 "1.0",
53 "wrong",
54 "225.0",
55 "3.00045",
56 "-4.0",
57 "5.104",
58 "5.25251525353",
59 ];
60 let s = StringChunked::from_slice(PlSmallStr::from_str("test"), &vals);
61 let s = s.to_decimal_infer(6).unwrap();
62 assert_eq!(s.dtype(), &DataType::Decimal(6, 5));
63 assert_eq!(s.len(), 7);
64 assert_eq!(s.get(0).unwrap(), AnyValue::Decimal(100000, 6, 5));
65 assert_eq!(s.get(1).unwrap(), AnyValue::Null);
66 assert_eq!(s.get(3).unwrap(), AnyValue::Decimal(300045, 6, 5));
67 assert_eq!(s.get(4).unwrap(), AnyValue::Decimal(-400000, 6, 5));
68 assert_eq!(s.get(6).unwrap(), AnyValue::Decimal(525252, 6, 5));
69 }
70}