代码之家  ›  专栏  ›  技术社区  ›  Nickolay

从HashMap中获取拥有值的Vec

  •  0
  • Nickolay  · 技术社区  · 5 年前

    我写的一个算法构建了一个临时的 HashMap . 一旦完成,我只对 values 所以我想从 HashMap<K, V> 给一个 Vec<V> .

    使用简化的示例hashmap:

    fn main() {
        use std::collections::HashMap;
        let mut h: HashMap<_, _> = HashMap::new();
        h.insert(1, "foo".to_owned());
    }
    

    我能做到:

    • let vals: Vec<&String> = h.values().collect(); -它很短很甜,但是hashmap仍然拥有这些值;
    • let vals: Vec<String> = h.values().cloned().collect() (如 this question )-结果就是我需要的,但我被教导要避免额外的克隆;
    • let vals: Vec<String> = h.into_iter().map(|(_k, v)| v).collect(); -做我不需要克隆的事,但有点难看。

    实际值是中等大小的结构( {String, Vec<String>} ,总共低于KB)。

    我是否应该避免 clone 在这种情况下还是过早优化?有没有一种我不知道的惯用方法?

    0 回复  |  直到 5 年前
        1
  •  1
  •   Stargateur    5 年前

    .into_iter().map(|(_, v)| v) 是惯用的方法。一点也不难看。

    如果你愿意,你可以:

    use std::collections::hash_map;
    use std::collections::HashMap;
    use std::iter::{ExactSizeIterator, FusedIterator};
    
    struct IntoValues<K, V> {
        iter: hash_map::IntoIter<K, V>,
    }
    
    impl<K, V> IntoValues<K, V> {
        fn new(map: HashMap<K, V>) -> Self {
            Self {
                iter: map.into_iter(),
            }
        }
    }
    
    impl<K, V> Iterator for IntoValues<K, V> {
        type Item = V;
    
        fn next(&mut self) -> Option<Self::Item> {
            self.iter.next().map(|(_, v)| v)
        }
    
        fn size_hint(&self) -> (usize, Option<usize>) {
            self.iter.size_hint()
        }
    }
    impl<K, V> ExactSizeIterator for IntoValues<K, V> {}
    
    impl<K, V> FusedIterator for IntoValues<K, V> {}
    
    trait HashMapTool {
        type IntoValues;
        type Item;
        fn into_values(self) -> Self::IntoValues;
    }
    
    impl<K, V> HashMapTool for HashMap<K, V> {
        type Item = V;
        type IntoValues = IntoValues<K, V>;
        fn into_values(self) -> Self::IntoValues {
            IntoValues::new(self)
        }
    }
    
    fn main() {
        let mut h: HashMap<_, _> = HashMap::new();
        h.insert(1, "foo".to_owned());
    
        let _vals: Vec<_> = h.into_values().collect();
    }