vortex_array/arrays/varbin/compute/
min_max.rs

1use itertools::Itertools;
2use vortex_dtype::DType;
3use vortex_error::VortexResult;
4use vortex_scalar::Scalar;
5
6use crate::accessor::ArrayAccessor;
7use crate::arrays::{VarBinArray, VarBinVTable};
8use crate::compute::{MinMaxKernel, MinMaxKernelAdapter, MinMaxResult};
9use crate::register_kernel;
10
11impl MinMaxKernel for VarBinVTable {
12    fn min_max(&self, array: &VarBinArray) -> VortexResult<Option<MinMaxResult>> {
13        compute_min_max(array, array.dtype())
14    }
15}
16
17register_kernel!(MinMaxKernelAdapter(VarBinVTable).lift());
18
19/// Compute the min and max of VarBin like array.
20pub fn compute_min_max<T: ArrayAccessor<[u8]>>(
21    array: &T,
22    dtype: &DType,
23) -> VortexResult<Option<MinMaxResult>> {
24    let minmax = array.with_iterator(|iter| match iter.flatten().minmax() {
25        itertools::MinMaxResult::NoElements => None,
26        itertools::MinMaxResult::OneElement(value) => {
27            let scalar = make_scalar(dtype, value);
28            Some(MinMaxResult {
29                min: scalar.clone(),
30                max: scalar,
31            })
32        }
33        itertools::MinMaxResult::MinMax(min, max) => Some(MinMaxResult {
34            min: make_scalar(dtype, min),
35            max: make_scalar(dtype, max),
36        }),
37    })?;
38
39    Ok(minmax)
40}
41
42/// Helper function to make sure that min/max has the right [`ScalarValue`] type.
43fn make_scalar(dtype: &DType, value: &[u8]) -> Scalar {
44    match dtype {
45        DType::Binary(_) => Scalar::new(dtype.clone(), value.into()),
46        DType::Utf8(_) => {
47            // Safety:
48            // We trust the array's dtype here
49            let value = unsafe { str::from_utf8_unchecked(value) };
50            Scalar::new(dtype.clone(), value.into())
51        }
52        _ => unreachable!(),
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use vortex_buffer::BufferString;
59    use vortex_dtype::DType::Utf8;
60    use vortex_dtype::Nullability::Nullable;
61    use vortex_scalar::Scalar;
62
63    use crate::arrays::VarBinArray;
64    use crate::compute::{MinMaxResult, min_max};
65    use crate::stats::{Stat, StatsProvider};
66
67    #[test]
68    fn some_nulls() {
69        let array = VarBinArray::from_iter(
70            vec![
71                Some("hello world"),
72                None,
73                Some("hello world this is a long string"),
74                None,
75            ],
76            Utf8(Nullable),
77        );
78        let MinMaxResult { min, max } = min_max(array.as_ref()).unwrap().unwrap();
79
80        assert_eq!(
81            min,
82            Scalar::new(
83                Utf8(Nullable),
84                BufferString::from("hello world".to_string()).into(),
85            )
86        );
87        assert_eq!(
88            max,
89            Scalar::new(
90                Utf8(Nullable),
91                BufferString::from("hello world this is a long string".to_string()).into()
92            )
93        );
94    }
95
96    #[test]
97    fn all_nulls() {
98        let array = VarBinArray::from_iter(vec![Option::<&str>::None, None, None], Utf8(Nullable));
99        let stats = array.statistics();
100        assert!(stats.get(Stat::Min).is_none());
101        assert!(stats.get(Stat::Max).is_none());
102    }
103}