更新日:
【Ruby】 ハッシュ(Hash)とは?初心者向けに図と豊富なコードで解説!
ハッシュとは、キーと値の組み合わせをセットにして複数のデータを管理することが出来る便利なオブジェクトのことです。
例えば、以下の画像のようにHash(ハッシュ)を使う事で「果物の名前、値段」(例: Apple, 150円)をセットして管理する事が出来ます。
1
2
3
# filename: irb | Hashの使用例
irb(main):001:0> fruits = { "Apple" => "150円", "Orange" => "100円", "Melon" => "600円", "Grape" => "700円" }
=> {"Apple"=>"150円", "Orange"=>"100円", "Melon"=>"600円", "Grape"=>"700円"}
配列では、添字を指定することによって、要素の変更を行なっていましたが、Hash(ハッシュ)ではキーを指定することで値を変更します。
1
2
3
4
5
# filename: irb | Appleのキー名を指定して要素の変更を行う
irb(main):002:0> fruits["Apple"] = "180円"
=> "180円"
irb(main):003:0> fruits
=> {"Apple"=>"180円", "Orange"=>"100円", "Melon"=>"600円", "Grape"=>"700円"}
配列が分からないという方は、「配列とは?」の記事を参考にして下さい。
Hash(ハッシュ)の使い方
この章では、Hashの使い方について1つ1つ丁寧に解説します。
Rubyでハッシュを作ってみよう!
ハッシュは、{}を使って定義します。
後ほどシンボルの箇所で詳しく説明しますが、キーと値をハッシュに格納する際にハッシュロケット(=>)を使って記述します。
ハッシュに格納するキーと値の組み合わせが複数ある場合は、{}内にカンマ区切りで記述します。
1
2
3
4
5
6
7
8
# 空のハッシュを定義
{}
# キーと値の組み合わせを3つの格納するハッシュ
{ "キー1" => "値1", "キー2" => "値2", "キー3" => "値3" }
# 変数aに3つのキーと値の組み合わせが格納されたハッシュを代入する
a = { "キー1" => "値1", "キー2" => "値2", "キー3" => "値3" }
上記はどれもHashクラスのオブジェクトになります。オブジェクトのクラスを調べることができる「classメソッド」で確認してみます。
1
2
3
4
5
6
7
8
# filename: irb | オブジェクトのクラスを調べる
irb(main):001:0> {}.class
=> Hash
irb(main):002:0> { "キー1" => "値1", "キー2" => "値2", "キー3" => "値3" }.class=> Hash
irb(main):003:0> a = { "キー1" => "値1", "キー2" => "値2", "キー3" => "値3" }
=> {"キー1"=>"値1", "キー2"=>"値2", "キー3"=>"値3"}
irb(main):004:0> a.class
=> Hash
上記より、全てHashクラスのオブジェクトという事が分かります。
RubyではHash(ハッシュ)という名前ですが、他の言語では連想配列やマップと呼ばれる場合があります。また、Hash.newでもハッシュを作成することが出来ますが、この記事では特に扱いません。
ハッシュの{}とブロックの{}の違い
ハッシュを定義する際に{}を使っていましたが、Rubyでは他にもブロックで{}を使います。この2つは書き方を誤ってしまうと、Ruby自身がハッシュの{}なのかブロックの{}なのか分からなくなる場合があります。
Rubyでは、メソッド呼び出し時に()を省略する事が出来ます。
1
2
3
4
5
6
7
# ()ありのメソッド呼び出し
puts ('Hello')
Hello=> nil
# ()を省略してメソッドを呼び出し
puts 'Hello'
Hello=> nil
putsメソッドについて詳しく知りたい方は、「putsメソッドの使い方」を参考にして下さい。
これは自作で定義したメソッドも適用されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
def hello(name)
puts "#{name},hello!"
end
# ()ありのメソッド呼び出し
hello("taro")
taro,hello!
=> nil
# ()を省略してメソッド呼び出し
hello "taro"
taro,hello!
=> nil
メソッドの第一引数がハッシュかつ、()を省略してメソッドを呼び出す場合、Rubyがハッシュの{}ではなく、ブロックの{}と解釈してエラーが出てしまいます。
1
2
3
4
5
6
7
8
9
# サンプルコードでエラーを検証
def buy_ice(options={}, menu)
puts options
end
# ()を省略してbuy_iceメソッドを呼び出すと、ハッシュの{}がブロックの{}と解釈されるのでエラーが起こる
buy_ice {'Strawberry' => true, 'Chocolate' => true}, 'ice'
SyntaxError (syntax error, unexpected =>, expecting '}')
メソッド引数の第一引数がハッシュの場合は、()をつけてメソッドを呼び出す事でブロックの{}だと解釈されずにメソッドを呼び出す事ができます。
1
2
3
buy_ice( { 'Strawberry' => true, 'Chocolate' => true }, 'ice')
{"Strawberry"=>true, "Chocolate"=>true}
=> nil
このようにメソッドの第一引数がハッシュの場合は、()を省略せずにメソッドを呼び出しましょう。
1
2
3
4
5
6
7
8
9
# 第二引数がハッシュの場合
def buy_ice(menu, options={})
puts options
end
# メソッド呼び出し時に{}も省略する事が出来る
buy_ice 'ice', 'Strawberry' => true, 'Chocolate' => true
{"Strawberry"=>true, "Chocolate"=>true}
=> nil
ハッシュの基本的な操作
ハッシュは、キーを指定することによって値を変更したり取得する事が出来ます。
上記のイメージのコードに置くと、次の様になります。
1
fruits = { "Apple" => "150円", "Orange" => "100円", "Melon" => "600円", "Grape" => "700円" }
このコードを使ってハッシュの基本的な操作を解説させて頂きます。
要素の追加と変更方法
ハッシュに新たに要素を追加するには、下記の様な構文を使います。
1
2
3
4
5
6
7
8
9
10
# ハッシュに新たな要素を追加する
ハッシュ[キー] = 追加する値
# イチゴを追加する
fruits['Strawberry'] = "500円"
=> "500円"
# イチゴが追加されているか確認する
fruits
=> {"Apple"=>"150円", "Orange"=>"100円", "Melon"=>"600円", "Grape"=>"700円", "Strawberry"=>"500円"}
ハッシュの中に同名のキーが存在していた場合に、元の値は新たな値に上書きされるので注意してください。
要素の変更をする際には、下記の様な構文になります。
1
2
3
4
5
6
7
8
9
ハッシュ[変更する要素のキー] = 変更する値
# 先ほどのイチゴの値段を500円から600円に変更する
fruits["Strawberry"] = '600円'
=> "600円"
# 変更されているか確認する
fruits
=> {"Apple"=>"150円", "Orange"=>"100円", "Melon"=>"600円", "Grape"=>"700円", "Strawberry"=>"600円"}
要素の取得方法
要素を取得するには、下記の様な構文になります。
ハッシュは、大量のキーと値が格納されていてもハッシュの内部構造によって高速に指定したキーの値を取得する事が可能です。
1
2
3
4
5
ハッシュ[キー]
# キーの"Apple"から値段を取得する
fruits["Apple"]
=> "150円"
先ほどのイメージの中で各果物の値段を取得するには、このように指定してあげると欲しい値段を取り出すことが出来ます。
また、指定したキーがない場合はnilを返します。
1
2
fruits["pear"]
=> nil
ハッシュの要素数を調べる方法
ハッシュの要素数を調べるには、sizeメソッドを使います。(エイリアスはlengthメソッド)
1
2
3
4
5
6
7
8
9
10
11
# ハッシュの要素数を調べる
{}.size
=> 0
# ハッシュが格納されているfruitsの中身を確認する
fruits
=> {"Apple"=>"150円", "Orange"=>"100円", "Melon"=>"600円", "Grape"=>"700円", "Strawberry"=>"600円"}
# fruitsの要素数を調べる
fruits.size
=> 5
要素を削除する方法
ハッシュの要素を削除するには、deleteメソッドを使います。指定したキーに対応する要素を削除します。
1
2
3
4
5
6
7
8
9
10
11
12
# filename: irb
# Appleに対応する要素を削除する
fruits.delete('Apple')
=> "150円"
# Appleと'150円'の組み合わせが削除されている
fruits
=> {"Orange"=>"100円", "Melon"=>"600円", "Grape"=>"700円", "Strawberry"=>"600円"}
# 指定したキーがない場合nilが返る
fruits.delete('pear')
=> nil
戻り値は、削除した要素になります。指定したキーがない場合はnilが返ります。
deleteにブロックを渡してあげると、指定したキーがない場合nillではなく、ブロックの戻り値にする事が出来ます。
1
2
fruits.delete('pear') { |key| " #{key}の対応する要素はありません"}
=> " pearの対応する要素はありません"
ハッシュを使った繰り返し処理
ハッシュはeachメソッドを使うと、キーと値を順番に取得する事が出来ます。配列の時とは違いブロック引数がキーと値の2種類になっているので注意してください。
1
2
3
4
5
6
7
8
9
10
# fruitsに格納されている順番にkey, valueにそれぞれキーと値を渡してブロック内の処理を実行させている
fruits.each do | key, value |
puts "#{key}は、#{value}"
end
Orangeは、100円
Melonは、600円
Grapeは、700円
Strawberryは、600円
=> {"Orange"=>"100円", "Melon"=>"600円", "Grape"=>"700円", "Strawberry"=>"600円"}
ブロックに渡した引数は「key, value」の2個でしたが、引数を1個だけにすると、キーと値が配列に格納されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# ブロックに渡す引数を1つにすると配列に格納される
fruits.each do | key_value |
puts "#{key_value}"
end
# キーと値はそれぞれ添字0,1に格納される
["Orange", "100円"]
["Melon", "600円"]
["Grape", "700円"]
["Strawberry", "600円"]
=> {"Orange"=>"100円", "Melon"=>"600円", "Grape"=>"700円", "Strawberry"=>"600円"}
# キーと値をブロック内で使うには、配列から取り出す処理を追加
fruits.each do | key_value |
key = key_value[0]
value = key_value[1]
puts "#{key}は#{value}"
end
Orangeは100円
Melonは600円
Grapeは700円
Strawberryは600円
=> {"Orange"=>"100円", "Melon"=>"600円", "Grape"=>"700円", "Strawberry"=>"600円"}
プログラムの読み方などに不安がある方は、こちらの「Rubyふりがなプログラミング」も併用すると良いでしょう。
プログラムの処理の流れや用語を初学者向けに優しく教えてくれます。最初からややレベルの高い技術書に取り掛かるよりも、何冊か優しい書籍を挟むことで挫折せずに学習することができます。
プログラムの読み方、用語を優しく丁寧に解説しています。
ハッシュとシンボル
現在ハッシュのキーには文字列を使っていますが、シンボルを使うことが推奨されています。まずは文字列とシンボルの違いについて理解していきましょう。
シンボルとは?
シンボルとは、コロン(:)を使って任意の名前を定義します。シンボルは、シンボルクラスのオブジェクトです。
1
2
3
4
5
6
7
8
:シンボルの名前
# シンボルの例
:name
# シンボルクラスのオブジェクト
:name.class
=> Symbol
シンボルと文字列の違いとは?
シンボルはSymbolクラスのオブジェクトで、文字列はStringクラスのオブジェクトです。
シンボルは表面的には文字列と似ていますが、シンボルの中身は文字列とは違い整数で管理されています。その為、文字列よりも高速に処理出来ます。
シンボルは、「同じシンボルであれば同じオブジェクト」という特徴があります。実際に、オブジェクトのidを調べる「object_idメソッド」を使って見ていきましょう。
1
2
3
4
5
6
7
8
9
# 文字列は、同じ文字列でもオブジェクトidが違う
'pikawaka'.object_id => 70151245202480
'pikawaka'.object_id => 70151245128760
'pikawaka'.object_id => 70151248681680
# シンボルは同じシンボルであればオブジェクトidが同じ
:pikawaka.object_id => 1310428
:pikawaka.object_id => 1310428
:pikawaka.object_id => 1310428
同じシンボルが同じオブジェクトである事は、メモリの使用率などが良くなり文字列よりも処理の速度が上がります。これはハッシュのキーにも当てはまります。
また、シンボルの特徴にイミュータブルで文字列の様に破壊的な変更は出来ない為、変更されては困るものに使う事が出来ます。
参考: プロを目指す人のためのRuby入門(シンボル p151参考) 伊藤淳一
ハッシュのキーにシンボルを使う
シンボルをハッシュのキーに使うことによって、文字列よりも高速に値を取り出したり、イミュータブルで破壊的な変更がされないのでハッシュのキーを勝手に変更される事がありません。
ハッシュのキーには文字列ではなく、シンボルを使う様にしましょう。
1
2
3
4
5
6
7
8
9
10
11
12
# 文字列をハッシュのキーにした場合
fruits = { "Apple" => "150円", "Orange" => "100円", "Melon" => "600円", "Grape" => "700円" }
# 文字列でハッシュを取り出す
fruits[ "Apple"]
# シンボルをハッシュのキーにする場合
fruits = { :Apple => "150円", :Orange => "100円", :Melon => "600円", :Grape => "700円" }
# シンボルでハッシュを取り出す
fruits[:Apple]
=> "150円"
現在ハッシュロケット(=>)を使っていますが、キーをシンボルにした場合は、ハッシュロケットを省略する事ができます。
シンボルのコロンの位置が左から右に変わるので注意してください。
1
2
3
4
5
6
# ハッシュロケットがある場合
fruits = { :Apple => "150円", :Orange => "100円", :Melon => "600円", :Grape => "700円" }
# ハッシュロケットを省略する場合、コロンの位置を左から右に変更する
fruits = { Apple: "150円", Orange: "100円", Melon: "600円", Grape: "700 円" }
=> {:Apple=>"150円", :Orange=>"100円", :Melon=>"600円", :Grape=>"700円"}
ハッシュロケット(=>)は、Ruby1.8以前でハッシュを生成する際に使われていた記法なので、シンボルを使う際は上記の様な書き方にしましょう。
1
2
3
4
5
6
7
# ハイフンが入っていると下記の指定だとエラーが起こる
{ hoge-hoge: 1 }
syntax error, unexpected ':', expecting =>
# Ruby2.2ではシングルクォートかダブルクォートで囲って使う事が出来る
{ 'hoge-hoge': 1 }
=> {:"hoge-hoge"=>1}
この記事は以下の情報を参考にして執筆しました。
プロを目指す人のためのRuby入門 伊藤淳一
この記事のまとめ
- ハッシュは、キーと値の組み合わせをセットにして複数のデータを管理するHashクラスのオブジェクトのこと
- キーを指定することで値を変更することが出来る
- ハッシュのキーには、文字列ではなくシンボルを使おう!