[英]In-place modification, insertion or removal in the same function for hash maps in Rust
假设我有一个 hash map m: HashMap<K, V>
,一个键k: K
和一个值v: V
,并且想做以下事情:
m
在索引k
处不包含值,则在索引k
处插入v
。m
在索引k
处包含值w
,则将 function fn combine(x: V, y: V) -> Option<V>
应用于v
和w
,并且:
None
,则从m
中删除索引k
处的条目。Some(u)
,将索引k
处的值替换为u
。 有没有办法“就地”执行此操作,而无需调用多次访问、修改或删除k
处的值的函数?
我还想避免复制数据,所以理想情况下不需要克隆v
来将克隆提供给insert
并单独combine
。
我可以重写combine
以使用(可变)引用(或内联它),但不复制数据的愿望仍然存在。
深入研究Entry
文档,我注意到Entry
枚举的变体提供了就地修改、删除或插入条目的功能。
在采取std::collections::hash_map::Entry
进入 scope 之后,可以执行以下操作:
match m.entry(k) {
Entry::Occupied(mut oe) => {
let w = oe.get_mut();
match combine(v, w) {
Some(u) => { *w = u; },
None => { oe.remove_entry(); },
}
},
Entry::Vacant(ve) => { ve.insert(v); },
}
( 这是 Rust 操场上的 PoC。)
但是,这需要combine
将(可变)引用作为其第二个参数(在我的情况下这很好)。
在最坏的情况下,我设法通过一次访问、一次写入和一次删除密钥来完成。 最后一个键删除应该不是必需的,但我不确定它是否可以完成。 到目前为止,我已经尽力了。 我希望这有帮助!
好的,所以我想我们想使用条目 API 。
Entry
的完整方法列表在这里。
我想我们会按照以下顺序进行:
m
在索引k
处包含值w
:(再执行两步)k
处插入v
。 这可以通过使用.and_modify
然后.or_insert
来完成。 像这样的东西:
let map = // ... Initialize the map
// Do stuff to it
// ...
// Our important bit:
let mut delete_entry = false;
map.entry(k)
.and_modify(|w| { // If the entry exists, we modify it
let u = combine(v, w);
match u {
Some(y) => *w = y;
None => delete_entry = true;
}
}
)
.or_insert(v); // If it doesn't, we insert v
if delete_entry {
map.remove(k);
}
如果没有最后一个map.remove
访问权限,我认为没有办法完成所有三件事,所以这是我目前最好的尝试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.