有一个简单的方法来填充一个二维HashMap吗?在C++中,我可以这样做:
std::unordered_map<int,std::unordered_map<int,int>> 2dmap;
//...
2dmap[0][0] = 0;
2dmap[0][1] = 1;
//...在我的锈蚀项目中,我试图填写一个类似的地图:
let mut map: HashMap<i32, HashMap<i32, i32>> = HashMap::new();
//...fill the hash map here.我认为唯一能做到这一点的方法是构建每个子地图,然后将它们移动到超级地图中,如下所示:
let mut sub1: HashMap<i32, i32> = HashMap::new();
sub1.insert(0, 0);
sub1.insert(1, 1);
let mut map: HashMap<i32, HashMap<i32, i32>>::new();
map.insert(0, sub1);有没有一种更简洁的方法来做到这一点?
上面的代码是我的实际用例的简化,它使用枚举作为HashMap的索引。
enum Example {
Variant1,
Variant2,
//...
}这些变体中没有一个保存值。我使用这个语法从我的HashMap查找
let value = map[Example::Variant1][Example::Variant2];发布于 2017-03-23 18:19:53
在铁锈里,元组的效果真的很好。您可能应该只使用HashMap<(i32, i32), i32>。然后,您将得到一些与C++代码非常接近的内容。
let mut map: HashMap<(i32, i32), i32> = HashMap::new();
sub1.insert((0, 0), 0);
sub1.insert((0, 1), 1);
// ...当然,如果我们有一个像vec!这样的宏和RFC正在研制中。,那就太好了。使用这个答案中的宏,您可以编写:
let map = hashmap![(0,0) => 0, (0,1) => 1, ...];如果使用枚举,则不会发生任何变化--只需确保为其派生了Eq、PartialEq和Hash。
let mut sub1: HashMap<(Example, Example), i32> = HashMap::new();
sub1.insert((Example::Variant1, Example::Variant1), 0);
sub1.insert((Example::Variant1, Example::Variant2), 1);
// ...发布于 2017-03-23 18:28:57
使用entry API:
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.entry(0).or_insert_with(HashMap::new).insert(0, 0);
map.entry(0).or_insert_with(HashMap::new).insert(1, 1);
println!("{:?}", map);
println!("{}", map[&0][&1]);
}与C++不同,构造嵌套的HashMap并不是隐式的--您必须非常清楚地知道,您希望允许创建一个新的HashMap。
与另一个答案不同,这保留了原始数据结构和基于初始键获取整个地图子集的能力:
println!("{:?}", map.get(&0));
println!("{:?}", map.get(&0).and_then(|m| m.get(&1)));如果总是提供两个数值索引,那么元组是一个更好的解决方案,因为它更准确地建模了问题--只有一个真正的键,它恰好有两个组件。它还可能具有更好的数据局部性,因为有一个大内存块,而不是额外级别的指针追逐散列哈希。
发布于 2017-03-23 23:13:01
C++代码片段的简洁性归功于方便的operator [],如果映射中缺少该值,它将自动构造该值。虽然Rust在默认情况下不会这样做,但是很容易告诉它这样做,如Shepmaster的答案所示。
为了避免详细说明entry(key).or_insert_with(ValueType::new),可以将相当于C++的operator []的方法添加到Rust的HashMap中。毕竟,Rust有必要的工具--它支持使用特性向现有类型添加方法,并且它的特征大致相当于C++的默认构造函数。
C++表达式:
map[0][0] = 0;
map[0][1] = 1;将使用返回引用的方法(而不是operator [] )将其编写为以下Rust
*map.ensure(0).ensure(0) = 0;
*map.ensure(0).ensure(1) = 1;ensure将被声明为一个必须由希望获得该方法的代码导入的特性:
use std::collections::HashMap;
use std::hash::Hash;
trait MapDefault<K, V: Default> {
fn ensure(&mut self, key: K) -> &mut V;
}...and定义如下:
impl<K: Eq + Hash, V: Default> MapDefault<K, V> for HashMap<K, V> {
fn ensure(&mut self, key: K) -> &mut V {
self.entry(key).or_insert_with(V::default)
}
}如果能够为IndexMut定义HashMap,这将使表达式缩短为*map[0][0] = 0,这与C++的原始版本几乎完全一样,但遗憾的是,Rust不允许为来自其他模块的类型实现运算符。
https://stackoverflow.com/questions/42983662
复制相似问题