习惯的Rust索引过滤(numpy风格)



我在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;
}

我尝试过做类似的事情,它可以包装在宏中(还没有学会如何做到这一点),但我不确定如何使用迭代器来实际执行它。这至少在正确的轨道上吗?

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

你要找的东西

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,对float64s的可变引用。

然后在该迭代器上调用.filter(),这将创建一个新的迭代器,该迭代器只产生通过给定闭包的元素。作为参数给.filter()的闭包必须接受对迭代器中元素的不可变引用,因为闭包只允许检查元素,但不能改变它们;注意.filter()的签名表明闭包必须是FnMut(&Self::Item) -> bool(注意&);这就是"额外的"引用(&&)来自。因此,传递给filter()的闭包中的参数x的类型是对f64的可变引用的"不可变引用"。(a&&mut f64).

最后,在经过过滤的迭代器上调用for_each(),它将消费调用它的迭代器,并在每个元素上执行给定的闭包。由于闭包使用元素,它不仅获得引用(&&mut f64),而且获得实际的&mut f64

(示例)闭包只是通过*x = 1.赋一个新值。我们需要一个解引用步骤(*),因为我们不想给引用赋值(改变&mut f64指向的值),而是给引用指向的值赋值(改变&mut f64后面的值)。

你的例子的直接翻译是:

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]
}

最新更新