web-dev-qa-db-fra.com

Move partielle de la VEC de tuple

J'ai une Vec<(String, i64)> et avez besoin de itérer sur le Strings et les déplacer, puis itérer sur le i64s.

Cependant, si je déplace le Strings, je dois stocker le i64 Encore une fois dans un autre Vec:

let l: Vec<_> = l
    .into_iter()
    .map(|(string, int)| {
        drop(string);
        int
    })
    .collect();
                           
for i in l {
    process(i);
}

Comment puis-je itération sur le Strings et i64s séparément sans engendrer de performances supplémentaires.

La seule solution que je puisse penser à l'heure actuelle qui ne causera pas d'opérations supplémentaires consiste à stocker les Strings et i64s séparément.

9
Nils André

Vous pouvez utiliser std::mem::take() en itérant sur le Vec dans une première passe pour prendre la propriété de l'élément String tout en mettant un _ non-alloué Default à sa place. Cela vous permet de conserver le Vec sous sa forme d'origine, aucun conteneur supplémentaire n'est requis.

fn foo(mut inp: Vec<(String, i64)>) {
    // First pass over the Vec "extracts" the owned Strings, replacing the content
    // in the Vec by a non-allocating empty String, which is close to zero cost;
    // this leaves the Vec as is, so no intermediate representation is needed.
    for s in inp.iter_mut().map(|(s, _)| std::mem::take(s)) {
        // Process String
    }

    // Something happens

    // Second pass ignores the empty strings, processes the integers
    for i in inp.into_iter().map(|(_, i)| i) {
        // Process the integers
    }
}
12
user2722968

Si le type de liste peut être changé en Vec<Option<String>, i64> à partir de Vec<String, i64>, alors vous pouvez essayer de la manière suivante.

fn main() {
    let mut l = Vec::new();
    l.Push((Some("a".to_string()), 1i64));
    l.Push((Some("b".to_string()), 2));
    l.Push((Some("c".to_string()), 3));
    l.Push((Some("d".to_string()), 4));
    
    l.iter_mut().for_each(|(s, _)| {
        if let Some(x) = s.take() { 
            println!("Processing string: {}", x);
        }
    });

    l.iter().for_each(|(_, i)| {
        println!("Processing int: {}", i);
    });
}

terrain de je

7
Joe_Jingyu

Utilisez unzip pour les séparer:

fn main(){
    let original = vec![("a", 1), ("b", 2)];
    let (s, i): (Vec<_>, Vec<_>) = original.into_iter().unzip();
                           
    for a in s {
        println!("{}", a);
    }
    
    for b in i {
        println!("{}", b);
    }
}

terrain de je

3
Netwave