和其它语言的Dict,dict,Dictionary等不太一样,Rust的HashMap很独特。
let mut contacts = HashMap::new();
contacts.insert("Daniel", "798-1364");
contacts.insert("Ashley", "645-7689");
contacts.insert("Katie", "435-8291");
contacts.insert("Robert", "956-1745");
let temp = contacts.get("Daniel");
assert_eq!(Some(&"798-1364"), temp); // 注意:& ,不是 Some("798-1364")!
let temp2 = contacts.get(&"Daniel");
assert_eq!(Some(&"798-1364"), temp2); //注意:& ,不是 Some("798-1364")!
为了有代表性,设计了一个相对复杂的双层HashMap+内置Vec的结构,如果还不够有代表性,那就没办法了,具体如下:
HashMap<&str, HashMap<&str, Boxf32>>>>
一、insert
let mut hd: HashMap<&str, HashMap<&str, Boxf32>>>> = HashMap::new();
let mut tm1 = HashMap::new();
//方法一: 如果tm1没有“book1”key,则insert key为“book1”和相应元素值。
tm1.entry("book1").or_insert(Box::new(vec![1.0_f32]));
hd.insert("rust", tm1);
println!("insert rust hd=>{:?}", hd);
//方法二: 直接insert
let mut tm2 = HashMap::new();
tm2.insert("book1", Box::new(vec![2.0_f32]));
hd.insert("julia", tm2);
println!("insert julia hd=>{:?}", hd);
// insert: Rust允许相同key的重复操作,会进行覆盖操作。
let mut tm3 = HashMap::new();
tm3.insert("book1", Box::new(vec![2.0_f32]));
hd.insert("julia", tm3);
总体上,虽然操作上不如一些脚本语言一样简洁,但还算中规中矩。
二、remove
hd.remove("julia"); //删除"julia"对应的key-value对。
三、对vec内部元素的类似push的操作
对于上述hd变量,若要对其中的Vec的元素进行增加操作,是否和python,或其它语言一样?
可惜:Rust没有
hd["rust"]["book1"].push(3.0_f32);// error!
虽然,hd有以下的取值的方式:
&hd2["rust"]["book1"]
但是,
&hd2["rust"]["book1"].push(3.0_f32) //error!
如何办?
嘿嘿,get_mut(),醒醒,说你呢,该轮到你上场了。
(1)上面的类型
对于HashMap<&str, HashMap<&str, Box>>>类型,要对最里面进行增加元素操作:
hd.get_mut("rust").unwrap().get_mut("book1").unwrap().push(3.0_f32);
println!("addvalue =>hd:{:?}", hd);//可以看到,Vec元素增加了!
(2)HashMap<&str, Vec>类型
比如,对于HashMap<&str, Vec<f32>>类型,要对最里面Vec<f32>进行增加元素的操作(假设里面有“rust”key),可以:
hd.get_mut("rust").unwrap().push(3.0_f32);
四、HashMap的key,value值
1、总体的keys,values:
let keys = hd.keys();
println!("keys:{:?}", keys); // ["rust","julia"]
let values = hd.values();
println!("values :{:?}", values);
注意,有hd.values_mut(),但没有keys_mut(),具体使用法,可以查阅Rust官网。
2、某个key对应的值
let value_key = hd.get("rust").unwrap().clone();
println!("value_key :{:?}", value_key);
或 ,注意下面&
let value_key2 =&hd["rust"]["book1"] // =>[1,2]
3、判断某个key是否在
let bool_key = hd.contains_key("rust");
println!("bool_key :{:?}", bool_key);//true
五、HashMap循还
for key in hd.keys() {
println!("key:{:?}", key);
}
for (key, value) in &hd {
println!("key:{:?} value :{:?}", key, value);
}
for (key, value) in hd.iter() {
println!("=>key:{:?} value :{:?}", key, value);
}
或
let mut mp = HashMap::new();
mp.insert("a", 1);
mp.insert("b", 2);
mp.insert("c", 3);
//iter_mut()
for (_, val) in mp.iter_mut() {
*val *= 2;
}
//注意没有keys_mut()
for val in mp.values_mut() {
*val = *val + 10;
}
六、HashMap <=>Vec
1、HashMap =>Vec
let vec: Vec<(_, _)> = hd.into_iter().collect();
println!("vec :{:?}", vec);
2、Vec=>HashMap
(1) Vec<(&str,i32)>
let timber_resources: HashMap<&str, i32> =
[("Norway", 100),
("Denmark", 50),
("Iceland", 10)]
.iter().cloned().collect();
(2) Vec
let data =vec![1,2,3,4,5];
let mut mp2: HashMap = data.iter().map(|&x| (x, x * 10)).collect();
(3)双Vec=>HashMap
let names = vec!["WaySLOG", "Mike", "Elton"];
let scores = vec![60, 80, 100];
let score_map: HashMap<_, _> = names.iter()
.zip(scores.iter())
.collect();
println!("{:?}", score_map);
比如,我们有两个&str,如何变成HashMap
struct Cipher {
hp: HashMap,
}
impl Cipher {
fn new(map1: &str, map2: &str) -> Cipher {
let map = map1.chars()
.map(|x| x.to_string())
.zip(map2.chars().map(|y| y.to_string()))
.collect::>();
Cipher { hp: map }
}
}
七、HashMap =>range
1、range =>HashMap
let mut mp: HashMap<i64, i64> = (0..8).map(|x|(x, x*10)).collect();
mp.retain(|&k, _| k % 2 == 0);
assert_eq!(mp.len(), 4);
let data: HashMap<char, i32> =
"abcdefghijklmnopqrstuvwxyz".chars().enumerate().map(|(x, y)| (y, x as i32 + 1)).collect();
注意:暂时还没找到‘a’..’z’这种Range的简便方法,其它的好办!
//以下是错误的!!!!!!!!!!!
let data: HashMap = ('a'..'z').chars().enumerate().map(|(x, y)| (y, x as i32 + 1)).collect();
2、 HashMap=>Vec
let mut v: Vec<i64> = mp.iter().map(|(_, &val)| val).collect();
println!("v:{:?}", v);
八、keys
let mut contacts = HashMap::new();
contacts.insert("Daniel", "798-1364");
contacts.insert("Ashley", "645-7689");
contacts.insert("Katie", "435-8291");
contacts.insert("Robert", "956-1745");
let names: Vec<&str> = contacts.keys().into_iter().map(|&x| x).collect();
let nums: Vec<&str> = contacts.values().into_iter().map(|&x| x).collect();
注意,上面不能用iter(),只能用into_inter().
九、为什么 Rust 的 HashMap 很慢?
“默认情况下,Rust 的 HashMap 使用 SipHash 哈希算法,其旨在防止哈希表碰撞攻击,同时在各种工作负载上提供合理的性能。
虽然 SipHash 在许多情况下表现出竞争优势,但其中一个比其它哈希算法要慢的情况是使用短键,例如整数。这就是为什么 Rust 程序员经常观察到 HashMap 表现不佳的原因。在这些情况下,经常推荐 FNV 哈希,但请注意,它不具备与 SipHash 相同的防碰撞性。”
特此说明:此部分见:https://www.rust-lang.org/zh-CN/faq.html
关于HashMap的应用实证和优化,希望有机会做些尝试,毕竟这个关键性的数据结构,特别是量化研究。
十、其它常用的函数
1、is_empty()
2、len();
3、reserve()
4、drain();
5、capacity()
6、hasher()
7、with_capacity_and_hasher()
8、with_hasher()
9、shrink_to_fit()
10、entry()
11、clear()