在 Rust 中,有没有办法只对容器的一部分执行retain()?

Zek*_*eke 5 primes vector rust

我学习 Rust 是为了好玩,当编写一个返回第 n 个素数的函数时,我意识到我的解决方案感觉不优雅且浪费。

当我只想遍历其中尚未验证的部分时,我会遍历整个可能的素数列表。有没有办法在使用retain()函数时做到这一点?

我的主要问题是,我相信保留()函数是为 Vec 实现的,而不是为切片实现的。我尝试查看切片文档以获取更多想法,但找不到任何内容。

这是代码。

let mut prime_list: Vec<u32> = (2..n).collect();
let mut i: usize = 0;
while i < prime_list.len() {
    let prime: u32 = prime_list[i];
    prime_list.retain(
       |x| x <= &prime || x % &prime != 0);
    i += 1;
}
Run Code Online (Sandbox Code Playgroud)

所以问题出在函数调用上

prime_list.retain(
    |x| x <= &prime || x % &prime != 0);
Run Code Online (Sandbox Code Playgroud)

每次进入此循环时,我不需要检查列表中的每个元素,因为我知道我已经验证了“i”之前的元素。

但是,retain() 函数需要遍历整个容器,因此我在其中添加了一个检查 (x <= &prime || ...) 以忽略当前元素之前的所有元素。

我想做的是优雅地从位置“i”的元素开始,然后遍历列表删除元素。

我知道我可以用不太优雅的 while 或 for 循环来做到这一点,但我希望有一种 Rust 方法可以优雅地做到这一点。

谢谢你的帮助!

编辑:这里有一个可能的解决方案,使用 splitting 和 filter() ,感觉比我想象的更混乱......如果有更好的方法使用 filter() 方法和迭代器,我真的很感激右边的轻推方向。

// inside the while loop
let prime: u32 = prime_list[i];
let (left, right) = prime_list.split_at(i);

prime_list = left.iter()
    .chain(
         right.iter()
         .filter(|x| *x == &prime || *x % &prime != 0))
    .map(|&x| x)
    .collect();

i += 1;
Run Code Online (Sandbox Code Playgroud)

小智 0

这并不能完全解决你想要的问题,但我想作为一个写过一段时间 rust 的人,我应该尝试以一种更“rust-way”的方式来做这件事。

let mut primes = Vec::new();

for e in 2..100 {
    if primes.iter().all(|p| e % p != 0) {
        primes.push(e);
    }
}

println!("{:?}", primes);
Run Code Online (Sandbox Code Playgroud)

我将素数存储在一个单独的向量中,因为我想在进行过程中添加它。这确实比在迭代向量时尝试使用保留从向量中删除某些元素要优雅得多。

with_capacity如果你真的想变得更奇特,你可以通过使用并在获得第 n 个素数后停止来优化一点。

fn get_nth_prime(n: usize) -> u32 {
    let mut primes = Vec::with_capacity(n);
    let mut e = 2;

    while primes.len() < n {
        if primes.iter().all(|p| e % p != 0) {
            primes.push(e);
        }

        e += 1;
    }

    primes[n - 1]
}
Run Code Online (Sandbox Code Playgroud)