Skip to main content

runlength_arrow/
reduce.rs

1//! Length-weighted reductions for sequences of numeric values.
2//!
3//! These borrow the Arrow values directly, without copying, and use the core
4//! crate's reductions. Values must be a numeric type without nulls.
5
6use std::sync::Arc;
7
8use arrow_array::cast::AsArray;
9use arrow_array::{Array, ArrayRef, ArrowPrimitiveType, PrimitiveArray};
10use runlength::{RleLike, RleRef};
11
12use crate::error::{Error, Result};
13use crate::numeric::with_numeric_type;
14use crate::rle::ArrowRle;
15
16fn core_view<'a, T: ArrowPrimitiveType>(rle: &'a ArrowRle) -> Result<RleRef<'a, T::Native>> {
17    let values = rle.values.as_primitive::<T>();
18    if values.null_count() > 0 {
19        return Err(Error::UnexpectedNulls);
20    }
21    Ok(RleRef::from_ends(&rle.ends, values.values())?)
22}
23
24fn single<T: ArrowPrimitiveType>(value: Option<T::Native>) -> ArrayRef {
25    Arc::new(std::iter::once(value).collect::<PrimitiveArray<T>>())
26}
27
28impl ArrowRle {
29    /// The sum over all positions, as one value of the values' type. Integer
30    /// sums wrap on overflow.
31    pub fn sum(&self) -> Result<ArrayRef> {
32        with_numeric_type!(self.values, |T| Ok(single::<T>(Some(
33            core_view::<T>(self)?.sum()
34        ))))
35    }
36
37    /// The mean over all positions, or `None` if the sequence is empty.
38    pub fn mean(&self) -> Result<Option<f64>> {
39        with_numeric_type!(self.values, |T| Ok(core_view::<T>(self)?.mean()))
40    }
41
42    /// The variance over all positions with `ddof` delta degrees of freedom,
43    /// or `None` if `len() <= ddof`.
44    pub fn variance(&self, ddof: i64) -> Result<Option<f64>> {
45        with_numeric_type!(self.values, |T| Ok(core_view::<T>(self)?.variance(ddof)))
46    }
47
48    /// The standard deviation; see [`variance`](ArrowRle::variance).
49    pub fn std(&self, ddof: i64) -> Result<Option<f64>> {
50        Ok(self.variance(ddof)?.map(f64::sqrt))
51    }
52
53    /// The smallest value ignoring `NaN`, as one value (null if there is none).
54    pub fn min(&self) -> Result<ArrayRef> {
55        with_numeric_type!(self.values, |T| Ok(single::<T>(
56            core_view::<T>(self)?.min().copied()
57        )))
58    }
59
60    /// The largest value ignoring `NaN`, as one value (null if there is none).
61    pub fn max(&self) -> Result<ArrayRef> {
62        with_numeric_type!(self.values, |T| Ok(single::<T>(
63            core_view::<T>(self)?.max().copied()
64        )))
65    }
66}