惯用的Rust索引过滤(numpy样式)

myzjeezk  于 2023-01-30  发布在  其他
关注(0)|答案(2)|浏览(142)

我在python中初始化数组时使用的一个常见习惯用法是

arr = np.zeros(10)
x = np.linspace(-5,5,10)
arr[np.abs(x)<2] = 1.

也就是说,使用“视图”有条件地改变数组的元素。在Rust中有没有一种惯用的方法可以做到这一点(也可以使用向量或其他集合)?或者是唯一的选择:

let mut arr = [0.; 10];
let x = linspace::<f64>[-5., 5., 10];
let mut i = 0;
for ele in x
{
    if (ele < 2.) arr[i] = 1.;
    i += 1;
}

我尝试过做一些类似的事情,它可以被 Package 在一个宏中(还没有学会如何做),但是我不确定如何使用迭代器来实际执行它。

u.iter()
 .filter(|x: &&f64| x.abs()<1./3.)
 .map(|x: &f64| 1.);
zed5wv10

zed5wv101#

你要找的是

fn main() {
    let mut arr = [0.; 10];
    arr.iter_mut()
        .filter(|x: &&mut f64| x.abs() < 1. / 3.)
        .for_each(|x: &mut f64| *x = 1.);
}

我们使用.iter_mut()在可变引用上创建迭代器;我们需要.iter_mut(),因为我们要改变迭代器所基于的元素。迭代器产生的项将是&mut f64,对float 64 s的可变引用。
然后我们在那个迭代器上调用.filter(),它创建一个新的迭代器,只产生那些通过给定闭包的元素,我们作为.filter()的参数给出的闭包必须接受对迭代器中的元素的不可变引用,因为闭包只允许检查元素而不允许改变它们;注意,.filter()的签名表明闭包必须是FnMut(&Self::Item) -> bool(注意&);这就是“extra”引用(&&)的来源,因此传递给filter()的闭包中的参数x的类型是“对f64的可变引用的不可变引用“(&&mut f64)。
最后,我们在过滤后的迭代器上调用for_each(),它将消耗它所调用的迭代器,并在每个元素上执行给定的闭包。当闭包消耗元素时,它不仅得到引用(&&mut f64),而且得到实际的&mut f64
闭包(示例)只是通过*x = 1.赋值一个新值,我们需要一个解引用步骤(*),因为不想赋值给引用(改变&mut f64指向的内容),而是赋值给引用指向的值(改变&mut f64后面的值)。

lskq00tm

lskq00tm2#

您的示例的直接翻译为:

fn main() {
    let mut arr = [0_f64; 10]; //arr = np.zeros(10)
    let x = (-5..5); // x = np.arange(-5,5,10)
    for x in (-1..=1) {
        arr[(arr.len() as i32 + x) as usize % arr.len()] = 1.0 // arr[np.abs(x)<2] = 1.
    }
    println!("{arr:?}"); // [1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
}

相关问题