Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend Iterator with a "mean" method

Tags:

rust

I'm trying to implement a mean method for Iterator, like it is done with sum. However, sum is Iterator method, so I decided to implement trait for any type that implements Iterator:

pub trait Mean<A = Self>: Sized {
    fn mean<I: Iterator<Item = A>>(iter: I) -> f64;
}

impl Mean for u64 {
    fn mean<I: Iterator<Item = u64>>(iter: I) -> f64 {
        //use zip to start enumeration from 1, not 0
        iter.zip((1..))
            .fold(0., |s, (e, i)| (e as f64 + s * (i - 1) as f64) / i as f64)
    }
}

impl<'a> Mean<&'a u64> for u64 {
    fn mean<I: Iterator<Item = &'a u64>>(iter: I) -> f64 {
        iter.zip((1..))
            .fold(0., |s, (&e, i)| (e as f64 + s * (i - 1) as f64) / i as f64)
    }
}

trait MeanIterator: Iterator {
    fn mean(self) -> f64;
}

impl<T: Iterator> MeanIterator for T {
    fn mean(self) -> f64 {
        Mean::mean(self)
    }
}

fn main() {
    assert_eq!([1, 2, 3, 4, 5].iter().mean(), 3.);
}

Playground

The error:

error[E0282]: type annotations needed
  --> src/main.rs:26:9
   |
26 |         Mean::mean(self)
   |         ^^^^^^^^^^ cannot infer type for `Self`

Is there any way to fix the code, or it is impossible in Rust?

like image 834
fantom Avatar asked Jul 13 '26 02:07

fantom


1 Answers

like it is done with sum

Let's review how sum works:

pub fn sum<S>(self) -> S
where
    S: Sum<Self::Item>, 

sum is implemented on any iterator, so long as the result type S implements Sum for the iterated value. The caller gets to pick the result type. Sum is defined as:

pub trait Sum<A = Self> {
    pub fn sum<I>(iter: I) -> Self
    where
        I: Iterator<Item = A>;
}

Sum::sum takes an iterator of A and produces a value of the type it is implemented from.

We can copy-paste the structure, changing Sum for Mean and put the straightforward implementations:

trait MeanExt: Iterator {
    fn mean<M>(self) -> M
    where
        M: Mean<Self::Item>,
        Self: Sized,
    {
        M::mean(self)
    }
}

impl<I: Iterator> MeanExt for I {}

trait Mean<A = Self> {
    fn mean<I>(iter: I) -> Self
    where
        I: Iterator<Item = A>;
}

impl Mean for f64 {
    fn mean<I>(iter: I) -> Self
    where
        I: Iterator<Item = f64>,
    {
        let mut sum = 0.0;
        let mut count: usize = 0;

        for v in iter {
            sum += v;
            count += 1;
        }

        if count > 0 {
            sum / (count as f64)
        } else {
            0.0
        }
    }
}

impl<'a> Mean<&'a f64> for f64 {
    fn mean<I>(iter: I) -> Self
    where
        I: Iterator<Item = &'a f64>,
    {
        iter.copied().mean()
    }
}

fn main() {
    let mean: f64 = [1.0, 2.0, 3.0].iter().mean();
    println!("{:?}", mean);
    let mean: f64 = std::array::IntoIter::new([-1.0, 2.0, 1.0]).mean();
    println!("{:?}", mean);
}
like image 132
Shepmaster Avatar answered Jul 14 '26 21:07

Shepmaster



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!