【问题标题】:In Rust, is there a way to perform a retain() on only part of a container?在 Rust 中,有没有办法只在容器的一部分上执行 retain()?
【发布时间】:2019-10-30 02:52:58
【问题描述】:

我学习 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

我想做的是优雅地从位置“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;

【问题讨论】:

  • filter 这样的迭代器会起作用吗?我不太明白你的素数算法。
  • 非常感谢您的快速回复!我不确定 filter() 是否会起作用,因为我想在 while 循环之外改变并返回 prime_list 。如果我做了一个 filter() ,我是否不必收集结果并以某种方式将其重新分配给 prime_list 变量?我不确定我是否可以重新分配……但我可以快速尝试一下。
  • 好的,我更新了它,但我不确定这个解决方案是否更好。我用新的工作版本更新了帖子。
  • 我的意思更接近于prime_list[i..].iter().filter(|| {...}).collect::&lt;Vec&lt;_&gt;&gt;();
  • 这适用于收集我刚刚扫描过的矢量部分,但我想收集不需要扫描的部分以及这个过滤的部分。因此,在编辑中,我想我会在rust right.iter().filter(....) 处做类似于您的建议的事情,但是由于我想要两者,所以我首先要 split_at() 然后将它们 chain() 在一起。出于某种原因,因为它是引用的切片,所以在执行 collect() 之前,我必须将每个元素更改为值而不是引用。

标签: vector rust primes


【解决方案1】:

这并不能完全解决您想要的问题,但我想作为一个写过 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]
}

【讨论】:

  • 太棒了。谢谢 - 可能是我使用 filter() 或 retain() 来缩小我的可能素数列表的方法是不正确的。我仍然觉得,在编辑的脉络中必须有一种不那么模糊的方式。但我会对此进行更多研究。谢谢!
猜你喜欢
  • 2021-05-13
  • 1970-01-01
  • 2022-01-24
  • 1970-01-01
  • 1970-01-01
  • 2021-07-02
  • 2018-09-23
  • 2020-11-30
  • 2020-03-04
相关资源
最近更新 更多