我学习 Rust 是为了好玩,在编写返回第 n 个素数的函数时,我意识到我的解决方案让人感觉既不优雅又浪费。
当我只想遍历其中尚未验证的部分时,我会遍历整个可能素数列表。有没有办法在使用 retain() 函数时做到这一点?
我的主要问题是我认为 retain() 函数是为 Vec 实现的,而不是为切片实现的。我尝试查看 slice 文档以获取更多想法,但找不到任何内容。
这是代码。
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;
}
所以问题出在函数调用上
prime_list.retain(
|x| x <= &prime || x % &prime != 0);
我不需要每次进入这个循环时都检查列表中的每个元素,因为我知道我已经验证了“i”之前的元素。
但 retain() 函数需要遍历整个容器,所以我在其中添加了一个检查 (x <= &prime || ...) 以忽略当前元素之前的所有元素。
我想做的是优雅地从位置“i”的元素开始,然后通过列表删除元素。
我知道我可以用不太优雅的 while 或 for 循环来做到这一点,但我希望有一种 Rust 方式可以优雅地做到这一点。
感谢您的帮助!
编辑:这是一个可能的解决方案,使用拆分和 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;
最佳答案
这并不能完全解决您想要的问题,但我想我会尝试以一种更“使用rust 的方式”来做这件事,作为一个写过一段时间使用rust 的人。
let mut primes = Vec::new();
for e in 2..100 {
if primes.iter().all(|p| e % p != 0) {
primes.push(e);
}
}
println!("{:?}", primes);
我将素数存储在一个单独的向量中,因为我想在进行时添加到它。这确实感觉比在迭代向量时尝试使用保留从向量中删除某些元素要优雅得多。
如果您真的想要花哨一些,可以使用 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]
}
关于vector - 在 Rust 中,有没有办法只对容器的一部分执行 retain()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56615602/