2017-10-09 9 views
8

J'essaie de supprimer certains éléments d'un vecteur, en fonction d'un prédicat, et de collecter le résultat. Voici un (ne fonctionne pas) par exemple avec un résultat attendu:Existe-t-il un moyen de drainer des parties d'un vecteur en fonction d'un prédicat?

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]); 

Il en résulte l'erreur

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(); 
    |                ^^^^^ 

Il existe plusieurs alternatives que j'ai regardé, aucun d'entre eux semblent faire ce que je veux:

  • Vec::retain supprime les éléments du vecteur, mais ne rend pas la propriété des éléments supprimés.

  • v.drain(..).filter(condition).collect() renvoie la valeur correcte pour drained mais vide le vecteur entier.

+0

avez-vous essayé de convertir le tableau avec to_vec? 'let drained: Vec = filtre v.iter(). (| E | (* e)% 2 == 0) .to_vec(). Drain (..). Collect();' – aug2uag

Répondre

7

Non stable Rouille 1.20.0. Il y a une caractéristique de nuit instable appelé drain_filter qui fait exactement ce que vous voulez:

#![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]); 
} 

En tant que solution de contournement stable, vous pourrez peut-être utiliser Iterator::partition, mais il ne réutilise pas la mémoire:

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]); 
}