在 Rust 的 HashMap 中"插入或更新"操作的最佳实践是什么?



我正在寻找insert-or-update操作的最佳实践,因为它非常常用,我认为我们需要优化它的写作风格和效率。

假设以下场景:我得到了一个hashmap

let classes: HashMap(String, HashSet<String>) = HashMap::new()

用于存储学生和whos类。

数据应采用以下形式:

{ key: "ClassA", value: {"Bob", "Marry", "Jack"}},
{ key: "ClassB", value: {"Lee", "Tom"}},

现在我得到了一组新的学生和他/她的班级的数据,让我们假设:

{ name: "Alice", class: "ClassC"}

由于我不确定这个类是否已经出现在classesHashMap中,我需要先弄清楚它是否存在,如果存在,我将更新值,如果不存在,我则添加一个新的key->value对。

在不进行任何不必要的移动或复制的情况下,正确的方法是什么?基于其他答案,我尝试使用std::collections::hash_map::Entry,但失败了。

谢谢!

使用该映射的惯用方法如下:

use std::collections::HashSet;
use std::collections::HashMap;
fn main() {
let mut classes: HashMap<String, HashSet<String>> = HashMap::new();

let e = classes.entry(String::from("ClassA"));
e.or_default().insert(String::from("Alice"));
let e = classes.entry(String::from("ClassA"));
e.or_default().insert(String::from("Bob"));

dbg!(&classes);
}

HashMap::entry()函数返回一个Entry值,该值表示地图中包含的值或地图中的位置。这个Entry类型有很多函数可以访问包含的值,并在需要时创建它。在您的情况下,最容易使用的函数是or_default,如果值还不在映射中,它会创建一个默认值(一个空集(。

然后,由于映射中有一个对集合的可变引用,只需插入所需的值即可。

要获得插入或更新行为,我会用这种流畅的方式

classes.entry(String::from("ClassC"))
.or_default()
.insert(String::from("Alice"));

涵盖您的场景的测试示例

#[test]
fn test(){
// Arrange
let mut classes: HashMap<String, HashSet<String>> = HashMap::from([
(String::from("ClassA"), HashSet::from([String::from("Bob"), String::from("Marry"), String::from("Jack")])),
(String::from("ClassB"), HashSet::from([String::from("Lee"), String::from("Tom")])),
]);
let class_c = String::from("ClassC");
let alice = String::from("Alice");
// Act
classes.entry(class_c.clone())
.or_default()
.insert(alice.clone());
// Assert
let contains_class = classes.contains_key(&class_c);
let contains_alice = classes.get(&class_c)
.unwrap().contains(&alice);
assert_eq!(true, contains_class);
assert_eq!(true, contains_alice);
}

相关内容

最新更新