В Rust есть способ выполнить retain () только для части контейнера? - PullRequest
1 голос
/ 16 июня 2019

Я изучаю Rust для удовольствия, и когда я писал функцию, возвращающую n-е простое число, я понял, что мое решение кажется неэффективным и расточительным.

Я перебираю весь список возможных простых чисел, когда хочу перебрать только ту его часть, которая не была проверена. Есть ли способ сделать это при использовании функции retain ()?

Моя главная проблема заключается в том, что я считаю, что функция 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;
}

Так что проблема в вызове функции

prime_list.retain(
    |x| x <= &prime || x % &prime != 0);

Мне не нужно просматривать каждый элемент в моем списке каждый раз, когда я захожу в этот цикл, так как я знаю, что проверял элементы перед «i».

Но функция retain () должна пройти весь контейнер, поэтому я добавляю в него проверку (x <= & prime || ...), чтобы игнорировать все элементы перед текущим. </p>

То, что я хотел бы сделать, это элегантно начать с элемента в позиции '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;

1 Ответ

0 голосов
/ 16 июня 2019

Это не решает в точности то, что вы хотели, но я подумал, что я бы попытался сделать более "ржавый" способ сделать это как кто-то, кто некоторое время писал ржавчину.

let mut primes = Vec::new();

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

println!("{:?}", primes);

Я храню простые числа в отдельном векторе, потому что я хочу добавить его по мере продвижения.Это действительно выглядит намного элегантнее, чем пытаться использовать retain для удаления определенных элементов из вектора при его итерации по нему.

Если вы действительно хотите получить фантазию, вы можете немного оптимизировать, используя 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]
}
...