使用地图对象作为函数输入

Use map object as function input

我有一个计算浮点数迭代器方差的函数,我希望能够在使用 map 方法对其进行转换后在迭代器上调用此函数。

use num::Float;

fn compute_var_iter<'a, I, T>(vals: I) -> T
where
    I: Iterator<Item = &'a T>,
    T: 'a + Float + std::ops::AddAssign,
{
    // online variance function
    // Var = E[X^2] - E[X]^2 
    // corrects for 1/n -> 1/(n-1)

    let mut x = T::zero();
    let mut xsquare = T::zero();
    let mut len = T::zero();

    for &val in vals {
        x += val;
        xsquare += val * val;
        len += T::one();
    }

    ((xsquare / len) - (x / len) * (x / len)) / (len - T::one()) * len
}

fn main() {
    let a: Vec<f64> = (1..100001).map(|i| i as f64).collect();
    let b: Vec<f64> = (0..100000).map(|i| i as f64).collect();

    dbg!(compute_var_iter(&mut a.iter())); // this works
    dbg!(compute_var_iter(a.iter().zip(b).map(|(x, y)| x * y))); // this does not work
}

是否有一种高效的方法可以将 map 输出返回给迭代器,或者让函数将 map 对象作为输入,这样我们就可以避免 .collect() 并保持惰性执行?

您可以直接使用迭代器对象而不用收集:

use num::Float;

fn compute_var_iter<I, T>(vals: I) -> T
where
    I: Iterator<Item = T>,
    T: Float + std::ops::AddAssign,
{
    // online variance function
    // Var = E[X^2] - E[X]^2 
    // corrects for 1/n -> 1/(n-1)

    let mut x = T::zero();
    let mut xsquare = T::zero();
    let mut len = T::zero();

    for val in vals {
        x += val;
        xsquare += val * val;
        len += T::one();
    }

    ((xsquare / len) - (x / len) * (x / len)) / (len - T::one()) * len
}

fn main() {
    let a = (1..100001).map(|i| i as f64);
    let b = (0..100000).map(|i| i as f64);
    let c: Vec<f64> = (0..10000).map(|i| i as f64).collect();

    dbg!(compute_var_iter(a.clone())); // this works
    dbg!(compute_var_iter(c.iter().map(|i| *i))); // this works
    dbg!(compute_var_iter(a.zip(b).map(|(x, y)| x * y))); 
}

Playground

请注意,如果您打算多次使用迭代器,则需要克隆迭代器。此外,您实际上并不需要使用引用,因为数字通常是 Copy 并且成本与创建引用本身相同。