Rustでdefaultdict
RustでPythonのDefaultDictのようにデフォルト値を持ったハッシュマップを使いたい場合、 entry APIを使って、以下のようにすればよい。
let mut normal_map = std::collections::HashMap::<i32, i32>::new(); // normal_map[3]を呼ぶ。ただし、存在しなければmap[3] = 5とする。 // println!("{:?}", normal_map[3]); はできないことに注意する。 println!("{:?}", *normal_map.entry(3).or_insert(5)); // 5 // normal_map[4]に1を足す。ただし、存在しなければmap[4] = 5としてから1を足す。 (*normal_map.entry(4).or_insert(5)) += 1; println!("{:?}", *normal_map.entry(4).or_insert(5)); // 6 // normal_map[5]を6とする。ただし、存在しなければmap[5] = 5としてから6を代入する。 (*normal_map.entry(5).or_insert(5)) = 6; println!("{:?}", *normal_map.entry(5).or_insert(5)); // 6
ここで、HashMapに格納される値の型は基本型でなくてもよい。
例えば、Vec
let mut normal_map = std::collections::HashMap::<i32, Vec<i32>>::new(); // normal_map[3]を呼ぶ。ただし、存在しなければmap[3] = vec![]とする。 println!("{:?}", *normal_map.entry(3).or_insert(vec![])); // [] // normal_map[4]に2をpushする。ただし、存在しなければmap[4] = vec![]としてからpushする。 (*normal_map.entry(4).or_insert(vec![])).push(2); // [1] println!("{:?}", normal_map[&4]);
しかし、entry APIを使ったアクセスは書き込みだけでなく、値が格納されているかわからない場合には、読み込みの度にもmap.entry(3).or_insert(5)してdereferenceしなければならない。
でなければ値が格納されていない要素にアクセスされた場合、panicが発生する。
少々めんどくさい。
そういう時は、
GitHub - JelteF/defaultmap: A defaultmap for rust
を使う。これはデフォルト値をDefaultHashMap::new()で指定できるHashMapである。 defaultmapを使って、上記の例を書き直すと以下のようになる。
let mut normal_map = DefaultHashMap::<i32, i32>::new(5); println!("{}", normal_map[3]); normal_map[4] += 1; println!("{}", normal_map[4]); normal_map[5] = 6; println!("{}", normal_map[4]);
初期値は当然、コンテナ型でもよい。
let mut normal_map = DefaultHashMap::<i32, Vec<i32>>::new(vec![]); println!("{:?}", normal_map[3]); normal_map[4].push(2); println!("{:?}", normal_map[4]);
ほぼPythonのDefaultDictのように使えるのでかなり便利である。
stdに入っていてほしいレベル。
ここで、[]演算子を使ってアクセスする際にキーは参照ではないことに注意されたい。
normal_map[4]のように値を使う。(HashMapは[&4])
- 作者: Jim Blandy,Jason Orendorff,中田秀基
- 出版社/メーカー: オライリージャパン
- 発売日: 2018/08/10
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る