2015-10-02 12 views
5

Vorrei rimuovere elementi da un BTreeMap trovati tramite un'iterazione.Rimozione di elementi da BTreeMap rilevati tramite iterazione

Poiché non è possibile rimuovere elementi durante l'iterazione per ovvi motivi, ho messo gli elementi da eliminare in un vettore. Il problema principale è che non è possibile utilizzare un vettore di riferimenti, ma solo un vettore di valori. Tutte le chiavi per le quali è necessario rimuovere la voce devono quindi essere clonate (presupponendo che la chiave implementa il tratto Clone).

Ad esempio, questo breve campione non si compila:

#![feature(drain)] 
use std::collections::BTreeMap; 

pub fn clean() { 

    let mut map = BTreeMap::<String, i32>::new(); 


    let mut to_delete = Vec::new(); 

    { 
     for (k, v) in map.iter() { 
      if *v > 10 { 
       to_delete.push(k); 
      } 
     } 

    } 

    for k in to_delete.drain(..) { 
     map.remove(k); 
    } 

} 

genera i seguenti errori quando si compila:

src/lib.rs:21:9: 21:12 error: cannot borrow `map` as mutable because it is also borrowed as immutable [E0502] 
src/lib.rs:21   map.remove(k); 
         ^~~ 
src/lib.rs:20:5: 22:6 note: in this expansion of for loop expansion 
src/lib.rs:12:23: 12:26 note: previous borrow of `map` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `map` until the borrow ends 
src/lib.rs:12   for (k, v) in map.iter() { 
            ^~~ 
src/lib.rs:12:9: 16:10 note: in this expansion of for loop expansion 
src/lib.rs:24:2: 24:2 note: previous borrow ends here 
src/lib.rs:4 pub fn clean() { 
... 
src/lib.rs:24 } 

Modifica to_delete.push(k) con to_delete.push(k.clone()) rende questo frammento compilato correttamente. Tuttavia, è molto costoso se ogni chiave da eliminare deve essere clonata.

C'è una soluzione migliore?

$ rustc --version 
rustc 1.5.0-nightly (65d5c0833 2015-09-29) 
+2

Mi auguro che alla fine, 'BTreeMap' potrebbe ottenere un metodo come' scarico fn (& auto mut, Gamma ) '. Di rilievo è [questo proto RFC] (https://github.com/rust-lang/rfcs/issues/460), ma controlla [questo] (https://github.com/rust-lang/rfcs/ pull/1254) e [questo] (https://github.com/rust-lang/rfcs/pull/1257). – Shepmaster

+0

@Shepmaster - Ovviamente, la cosa qui è che non è Range , ma piuttosto Range LinearZoetrope

+0

@Jsor ah, mi sono perso. Sento che è un caso improbabile, quindi è davvero un caso appiccicoso! – Shepmaster

risposta

1

Probabilmente guarderei il problema da una direzione leggermente diversa. Invece di cercare di mantenere la mappa, avevo appena creare uno nuovo di zecca:

use std::collections::BTreeMap; 

pub fn main() { 
    let mut map = BTreeMap::new(); 

    map.insert("thief", 5); 
    map.insert("troll", 52); 
    map.insert("gnome", 7); 

    let map: BTreeMap<_, _> = 
     map.into_iter() 
     .filter(|&(_, v)| v <= 10) 
     .collect(); 

    println!("{:?}", map); // troll is gone 
} 
+0

Questa è un'idea interessante. – Teetoo

+1

Si noti che a seconda delle dimensioni della mappa rispetto al numero di elementi da rimuovere, questo non è un chiaro guadagno in termini di prestazioni. –