2015-10-02 13 views
5

Chciałbym usunąć elementy z BTreeMap, które zostały znalezione w iteracji.Usuwanie elementów z BTreeMap znalezionego w iteracji

Ponieważ nie można usunąć przedmiotów podczas iteracji z oczywistych powodów, umieszczam elementy do usunięcia w wektorze. Głównym problemem jest to, że nie jest możliwe użycie wektora o referencjach, ale tylko wektor wartości. Wszystkie klucze, których wpis musi zostać usunięty, muszą zostać sklonowane (zakładając, że klucz implementuje cechę Clone).

Na przykład, ta krótka próbka nie kompilacji:

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

} 

Generuje następujące błędy podczas kompilacji:

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 } 

Zmiana to_delete.push(k) z to_delete.push(k.clone()) sprawia, że ​​ten fragment kompiluje poprawnie. Ale jest to dość kosztowne, jeśli każdy klucz do usunięcia musi zostać sklonowany.

Czy istnieje lepsze rozwiązanie?

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

Mam nadzieję, że w końcu, 'BTreeMap' może uzyskać metodę jak' drenażu Fn (& mut siebie, Rząd ) '. Istotne jest [to proto RFC] (https://github.com/rust-lang/rfcs/issues/460), ale sprawdź [to] (https://github.com/rust-lang/rfcs/ pull/1254) i [ten] (https://github.com/rust-lang/rfcs/pull/1257). – Shepmaster

+0

@Shepmaster - Oczywiście, chodzi o to, że nie jest to Zakres , ale raczej Zakres LinearZoetrope

+0

@Jsor ah, tęskniłem za tym. Uważam, że jest to mało prawdopodobny przypadek, więc jest to rzeczywiście przykra sprawa! – Shepmaster

Odpowiedz

1

Pewnie spojrzałbym na problem z nieco innej strony. Zamiast próbować zachować mapę, ja po prostu stworzyć markę nową:

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

To jest ciekawy pomysł. – Teetoo

+1

Należy zauważyć, że w zależności od rozmiaru mapy w porównaniu do liczby elementów, które mają zostać usunięte, nie jest to wyraźny zysk pod względem wydajności. –

Powiązane problemy