Подтвердить что ты не робот

Есть ли способ дренировать части вектора на основе предиката?

Я пытаюсь удалить некоторые элементы из вектора на основе предиката и собрать результат. Здесь (не работает) пример с ожидаемым результатом:

let mut v: Vec<i32> = vec![1, 2, 3, 4, 5, 6];

let drained: Vec<i32> = v.iter().filter(|e| (*e) % 2 == 0).drain(..).collect();

assert_eq!(v, vec![1, 3, 5]);
assert_eq!(drained, vec![2, 4, 6]);

Это приводит к ошибке

error[E0599]: no method named `drain` found for type `std::iter::Filter<std::slice::Iter<'_, i32>, [[email protected]/main.rs:4:45: 4:62]>` in the current scope
 --> src/main.rs:4:64
  |
4 |     let drained: Vec<i32> = v.iter().filter(|e| (*e) % 2 == 0).drain(..).collect();
  |                                                                ^^^^^

Есть несколько альтернатив, на которые я смотрел, ни один из них, похоже, не делает то, что я хочу:

  • Vec::retain удаляет элементы из вектора, но не возвращает права собственности на удаленные элементы.

  • v.drain(..).filter(condition).collect() возвращает правильное значение для drained, но опустошает весь вектор.

4b9b3361

Ответ 1

Не в стабильном русте 1.33.0. Есть нестабильная ночная функция, которая называется drain_filter которая делает именно то, что вы хотите:

#![feature(drain_filter)]

fn main() {
    let mut v: Vec<i32> = vec![1, 2, 3, 4, 5, 6];

    let drained: Vec<i32> = v.drain_filter(|&mut e| e % 2 == 0).collect();

    assert_eq!(v, vec![1, 3, 5]);
    assert_eq!(drained, vec![2, 4, 6]);
}

В качестве стабильного обходного пути вы можете использовать Iterator::partition, но он не использует память повторно:

fn main() {
    let v: Vec<i32> = vec![1, 2, 3, 4, 5, 6];

    let (drained, v): (Vec<_>, Vec<_>) = v.into_iter().partition(|&e| e % 2 == 0);

    assert_eq!(v, vec![1, 3, 5]);
    assert_eq!(drained, vec![2, 4, 6]);
}