Rustの基礎 - 辞書
概要
HashMap (ハッシュマップ) とは、複数のデータ型を管理することができるコレクション型である。
連想配列とも呼ばれる。
HashMapの特徴は、要素を格納する時に、キーを使用して管理することができる。
RustのHashMapは標準ライブラリに含まれているが、使用する場合には std::collections::HashMap をインポートする必要がある。
HashMapは要素の順番を保持しない。
順番を保持したい場合は、BTreeMap や IndexMap 等の別のデータ構造を使用する。
HashMapの定義
HashMapを使用するには、std::collections::HashMap をインポートする必要がある。
HashMapの作成には、new メソッドを使用、または、マクロを使用する方法がある。
基本的な宣言方法は、HashMap::new()で空のHashMapを生成して、insert メソッドで要素を追加する。
use std::collections::HashMap;
// 空のHashMapを作成
let mut map = HashMap::new();
// 要素を追加
map.insert("x", 100);
map.insert("y", 200);
map.insert("z", 300);
また、最初から値を持つHashMapを作成することもできる。
use std::collections::HashMap;
let mut map = HashMap::from([
("x", 100),
("y", 200),
("z", 300),
]);
HashMapの操作
HashMapはキーでそれぞれの値を抽出することができる。
get メソッドを使用してキーを指定することで、値を取得できる。
get メソッドはOption型を返すため、値が存在しない場合に安全に処理できる。
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("x", 100);
map.insert("y", 200);
// get()はOption<&V>を返すため、unwrap や .copied()を使用する
println!("{}", map.get("x").unwrap());
println!("{}", map.get("y").unwrap());
// 出力
100
200
次は、キーを指定して値を変更する。
insert メソッドで既存のキーに値を設定すると、値が上書きされる。
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("x", 100);
map.insert("y", 200);
// 既存のキーに新しい値を設定
map.insert("x", 300);
println!("{:?}", map);
// 出力
{"x": 300, "y": 200}
次に、新たにデータをHashMapに追加する。
以下の例では、新しいキーを指定して、新しい要素を追加している。(文字列のキーと数値のキーの両方で行う)
use std::collections::HashMap;
let mut map1 = HashMap::new();
map1.insert("x", 100);
map1.insert("y", 200);
map1.insert("z", 300);
// 数値のキーを持つHashMap
let mut map2 = HashMap::new();
map2.insert(10, 400);
println!("{:?}", map1);
println!("{:?}", map2);
// 出力
{"x": 100, "y": 200, "z": 300}
{10: 400}
イテレータからHashMapを作成する
HashMapは、イテレータを持つコレクション (配列、ベクター、タプル等) を collect メソッドを使用して変換して作成することができる。
それぞれキーと要素との2つの組み合わせになったものであることが必要である。
以下の例では、タプルの配列やベクタからcollectメソッドでHashMapに変換する。
use std::collections::HashMap;
// タプルの配列から作成
let pairs = [("a", "b"), ("c", "d"), ("e", "f")];
let map1: HashMap<_, _> = pairs.into_iter().collect();
// ベクターから作成
let vec_pairs = vec![("a", "b"), ("c", "d"), ("e", "f")];
let map2: HashMap<_, _> = vec_pairs.into_iter().collect();
println!("{:?}", map1);
println!("{:?}", map2);
// 出力
{"a": "b", "c": "d", "e": "f"}
{"a": "b", "c": "d", "e": "f"}
また、2つの別々のベクタから zip メソッドを使用してHashMapを作成することもできる。
use std::collections::HashMap;
let keys = vec!["x", "y"];
let values = vec![100, 200];
let map: HashMap<_, _> = keys.into_iter().zip(values.into_iter()).collect();
println!("{:?}", map);
// 出力
{"x": 100, "y": 200}
HashMapのメソッド
HashMap型には、様々なメソッドがある。
keysメソッド と valuesメソッド で全てのキーと値を取得する
これらのメソッドは、それぞれキーの全て、値の全てを取得する時に使用する。
イテレータを返すため、ループ処理や他のコレクションへの変換に使用できる。
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("x", 100);
map.insert("y", 200);
// キーを取得
for key in map.keys() {
println!("キー: {}", key);
}
// 値を取得
for value in map.values() {
println!("値: {}", value);
}
// 出力
キー : x
キー : y
値 : 100
値 : 200
extendメソッドでHashMapを結合する
extendメソッドは、2つの異なるHashMapを結合することができる。
キーが同じ場合は新しい値に更新する。
use std::collections::HashMap;
let mut map1 = HashMap::from([
("l", 10),
("m", 200),
("n", 300),
]);
let map2 = HashMap::from([
("l", 100),
("o", 400),
]);
map1.extend(map2);
println!("{:?}", map1);
// 出力
{"l": 100, "m": 200, "n": 300, "o": 400}
getメソッドで値を取得する
getメソッドを使用してキーを指定し、値を取得することができる。
getメソッドはOption<&V>を返すため、キーが存在しない場合にもパニックせず、Noneが返される。
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("x", 10);
map.insert("y", 20);
// 値を取得
let val = map.get("x");
match val {
Some(v) => println!("{}", v),
None => println!("キーが存在しません"),
}
// 出力
10
removeメソッドで値を取得して削除する
removeメソッドはキーを指定して値を取得し、HashMapからその要素を削除する。
Option<V>を返すため、キーが存在しない場合はNoneが返される。
use std::collections::HashMap;
let mut map = HashMap::from([
("x", 100),
("y", 200),
("z", 300),
]);
let value = map.remove("x");
println!("{:?}", value);
println!("{:?}", map);
// 出力
Some(100)
{"y": 200, "z": 300}
個別の要素を削除する
remove メソッドを使用すると、指定したキーの要素をHashMapから削除することができる。
use std::collections::HashMap;
let mut map = HashMap::from([
("x", 100),
("y", 200),
("z", 300),
]);
map.remove("y");
println!("{:?}", map);
// 出力
{"x": 100, "z": 300}
HashMapの変数自体が不要になった場合は、Rustの所有権システムによりスコープを抜けた時点で自動的にメモリが解放される。
{
let map = HashMap::new();
// mapを使用
} // ここでmapは自動的に解放される
clearメソッドで全ての要素を削除する
clearメソッドを使用すると、全ての要素を削除して空のHashMapが残り、HashMap自体の操作を続けることができる。
use std::collections::HashMap;
let mut map = HashMap::from([
("x", 100),
("y", 200),
("z", 300),
]);
map.clear();
println!("{:?}", map);
// 出力
{}
contains_keyメソッドでキーの有無を調べる
HashMapに指定するキーがあるかを調べるには、contains_key メソッドを使用する。
HashMapにキーが存在すればtrue、キーが存在しない場合はfalseを返す。
use std::collections::HashMap;
let mut map = HashMap::from([
("x", 100),
("y", 200),
("z", 300),
]);
println!("{}", map.contains_key("x"));
println!("{}", map.contains_key("a"));
// 出力
true
false
HashMapのクローン
HashMapをコピーするには、代入による所有権の移動と clone メソッドを使用する方法がある。
Rustの所有権システムにより、単純な代入では所有権が移動し、元の変数は使用できなくなる。
代入による所有権の移動
単純な代入では、所有権が移動するため、元の変数は使用できなくなる。
use std::collections::HashMap;
let mut map1 = HashMap::from([
("x", 100),
("y", 200),
("z", 300),
]);
let mut map2 = map1; // 所有権が移動
map2.insert("x", 500);
println!("{:?}", map2);
// println!("{:?}", map1); // エラー: map1は既に使用できない
// 出力
{"x": 500, "y": 200, "z": 300}
cloneメソッドで独立したコピーを作成する
全く独立した別のHashMapとして扱えるようにするには、clone メソッドを使用する。
cloneメソッドはディープコピーを行うため、一方を変更しても他方には影響しない。
use std::collections::HashMap;
let mut map1 = HashMap::from([
("x", 100),
("y", 200),
("z", 300),
]);
let mut map2 = map1.clone(); // クローンを作成
map2.insert("x", 500);
println!("{:?}", map1);
println!("{:?}", map2);
// 出力
{"x": 100, "y": 200, "z": 300}
{"x": 500, "y": 200, "z": 300}