1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
use crate::prelude::*;
use num::{NumCast, ToPrimitive, Zero};
use std::ops::Div;

// TODO: implement types
macro_rules! apply_agg_fn {
    ($self:ident, $agg:ident) => {
        match $self {
            Series::Bool(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast bool to T")),
            Series::UInt8(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast u8 to T")),
            Series::UInt16(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast u16 to T")),
            Series::UInt32(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast u32 to T")),
            Series::UInt64(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast u64 to T")),
            Series::Int8(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast i8 to T")),
            Series::Int16(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast i16 to T")),
            Series::Int32(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast i32 to T")),
            Series::Int64(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast i64 to T")),
            Series::Float32(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast f32 to T")),
            Series::Float64(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast f64 to T")),
            Series::Date32(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast Date64 to T")),
            Series::Date64(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast Date64 to T")),
            Series::Time32Millisecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast Time32Millisecond to T")),
            Series::Time32Second(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast Time32Second to T")),
            Series::Time64Nanosecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast Time64Nanosecond to T")),
            Series::Time64Microsecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast Time64Microsecond to T")),
            Series::DurationNanosecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast DurationNanosecond to T")),
            Series::DurationMicrosecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast DurationMicrosecond to T")),
            Series::DurationMillisecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast DurationMillisecond to T")),
            Series::DurationSecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast DurationSecond to T")),
            Series::TimestampNanosecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast TimestampNanosecond to T")),
            Series::TimestampMicrosecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast TimestampMicrosecond to T")),
            Series::TimestampMillisecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast TimestampMillisecond to T")),
            Series::TimestampSecond(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast TimestampSecond to T")),
            Series::IntervalDayTime(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast IntervalDayTime to T")),
            Series::IntervalYearMonth(a) => a
                .$agg()
                .map(|v| T::from(v).expect("could not cast IntervalYearMonth to T")),
            Series::Utf8(_a) => unimplemented!(),
            Series::LargeList(_a) => unimplemented!(),
        }
    };
}

impl Series {
    /// Returns `None` if the array is empty or only contains null values.
    /// ```
    /// # use polars::prelude::*;
    /// let s = Series::new("days", [1, 2, 3].as_ref());
    /// assert_eq!(s.sum(), Some(6));
    /// ```
    pub fn sum<T>(&self) -> Option<T>
    where
        T: NumCast + Zero + ToPrimitive,
    {
        apply_agg_fn!(self, sum)
    }

    /// Returns the minimum value in the array, according to the natural order.
    /// Returns an option because the array is nullable.
    /// ```
    /// # use polars::prelude::*;
    /// let s = Series::new("days", [1, 2, 3].as_ref());
    /// assert_eq!(s.min(), Some(1));
    /// ```
    pub fn min<T>(&self) -> Option<T>
    where
        T: NumCast + Zero + ToPrimitive,
    {
        apply_agg_fn!(self, min)
    }

    /// Returns the maximum value in the array, according to the natural order.
    /// Returns an option because the array is nullable.
    /// ```
    /// # use polars::prelude::*;
    /// let s = Series::new("days", [1, 2, 3].as_ref());
    /// assert_eq!(s.max(), Some(3));
    /// ```
    pub fn max<T>(&self) -> Option<T>
    where
        T: NumCast + Zero + ToPrimitive,
    {
        apply_agg_fn!(self, max)
    }

    pub fn mean<T>(&self) -> Option<T>
    where
        T: NumCast + Zero + ToPrimitive + Div<Output = T>,
    {
        apply_agg_fn!(self, sum).map(|v| v / T::from(self.len()).unwrap())
    }
}

#[cfg(test)]
mod test {
    use crate::prelude::*;

    #[test]
    fn test_agg_bool() {
        let s = Series::new("", vec![true, false, true].as_slice());
        assert_eq!(s.max::<u8>(), Some(1));
        assert_eq!(s.min::<u8>(), Some(0));
    }
}