key
,value
が一対になったセット- ハッシュのクラス名 :
Hash
- ハッシュ、ハッシュオブジェクト、Hash オブジェクトなどと呼ぶ
h = {:key1 => "value", :key2 => 1}
p h[:key1] # "value"
p h[:key2] # 1
- キー → シンボル
{ "キー" => "値", "キー" => "値" }
↓
{:key1 => "value", :key2 => 1}
↓
{ "シンボルオブジェクト" => "文字列オブジェクト", "シンボルオブジェクト" => "整数オブジェクト" }
シンボル symbol
- シンボルは
:
(コロン)から書き始める- ダブルクォーテーションで囲まないので注意
- シンボルも文字列や整数と同じようにオブジェクトの一種
- シンボルのクラス名 :
Symbol
=>
: 親しみを込めてハッシュロケット
と呼ばれる- シンボルはハッシュのキーで、ラベルのような使い方をする
- ハッシュのキー以外でもシンボルは使われる
- シンボル / 文字列は相互に変換できる
p "coffee".to_sym
# :coffee
p :coffee.to_s
# "coffee"
ハッシュの 2 種類の書き方
パターン B
の方が読みやすいが、以下の条件がある- 「ハッシュのキーにシンボルを指定した時のみ」使える
- 「ハッシュのキーに文字列」など、シンボル以外のオブジェクトを使う場合は、
パターン A
を使う必要がある
# パターン A
{:coffee => 300, :latte => 400}
# パターン B
{coffee: 300, latte: 400}
# 「ハッシュのキーが文字列」のためハッシュロケットで書く
{"coffee" => 300, "latte" => 400}
ハッシュの要素へのアクセス
- シンボルでのアクセス
hash[:symbol]
menu = {coffee: 300, latte: 400}
p menu[:latte]
# 400
- キー名でのアクセス
hash["key_name"]
menu = {"coffee" => 300, "latte" => 400}
p menu["latte"]
# 400
要素の追加 / 更新 / 削除
追加
hash[:new_symbol]
- 新しい要素
menu[:mocha]
に500
を代入するイメージ - 新しい要素は末尾に追加される
- ただし、ハッシュは「キーを指定して値を取得する」ことが多いため、配列のように並び順を気にすることはあまりない
menu = {coffee: 300, latte: 400}
menu[:mocha] = 500
p menu[:mocha]
# 500
p menu
# {:coffee=>300, :latte=>400, :mocha=>500}
更新
- ハッシュは同じキーを持たない
- 既にあるキーを指定して登録すると、既存のものが上書きされる
menu = {coffee: 300, latte: 400}
menu[:mocha] = 500
p menu
# {:coffee=>300, :latte=>400, :mocha=>500}
menu[:mocha] = 650
p menu
# {:coffee=>300, :latte=>400, :mocha=>650}
値に追加して更新
menu = {coffee: 300, latte: 400}
menu[:coffee] += 100
p menu
# {:coffee=>400, :latte=>400}
menu = {coffee: "300", latte: 400}
menu[:coffee] += "100"
p menu
# {:coffee=>"300100", :latte=>400}
削除 delete
hash.delete(:symbol)
menu = {coffee: 300, latte: 400, mocha: 650}
menu.delete(:latte)
p menu
# {:coffee=>300, :mocha=>650}
ハッシュの結合 merge
menu1 = {coffee: 300, latte: 400}
menu2 = {apple: 200, banana: 300}
menu = menu1.merge(menu2)
p menu
# {:coffee=>300, :latte=>400, :apple=>200, :banana=>300}
存在しないキーを指定すると nil
が返る
menu = {coffee: 300, latte: 400}
p menu[:hoge]
# nil
ハッシュのループ
- 配列と同じように
each
メソッドでループを回せる- 変数が
|key, value|
と指定できる
- 変数が
menu = {coffee: 300, latte: 400}
menu.each { |k, v| p "#{k} is #{v}" }
# "coffee is 300"
# "latte is 400"
キーだけのループ each_key
menu = {coffee: 300, latte: 400}
menu.each_key { |k| p k }
# :coffee
# :latte
menu = {coffee: 300, latte: 400}
menu.each_key { |k| p k.to_s }
# "coffee"
# "latte"
menu = {coffee: 300, latte: 400}
array = []
menu.each_key {|k| array << k.to_s}
p array
# ["coffee", "latte"]
値だけのループ each_value
menu = {coffee: 300, latte: 400}
menu.each_value { |v| p v }
# 300
# 400
キー / 値を配列で取得
全キーを配列として取得 keys
menu = {"coffee" => 300, "latte" => 400}
p menu.keys
# ["coffee", "latte"]
値の全値を配列として取得 values
menu = {"coffee" => 300, "latte" => 400}
p menu.values
# [300, 400]
ハッシュを使った集計
banana
に登場するアルファベットそれぞれの合計数を集計する
banana
を 1 文字ずつ分解して配列にする- ハッシュの
キー
にアルファベット 1 文字、値
に登場回数をセットしていく
text = "banana"
array = text.chars
p array
# ["b", "a", "n", "a", "n", "a"]
hash = {}
array.each { |t| hash[t] += 1 }
# undefined method `+' for nil:NilClass (NoMethodError)
- 空のハッシュにキーを指定して、数値を追加(加算
+=
)するとエラーになる- 存在しないキーを指定すると
nil
が返るnil + 1
→ エラー
- 存在しないキーを指定すると
default
hash = {}
p hash.default # nil
hash.default = 0
p hash.default # 0
- 先ほどのエラーで止まったスクリプトに
default
メソッドを加える
text = "banana"
array = text.chars
p array
# ["b", "a", "n", "a", "n", "a"]
hash = {}
hash.default = 0
array.each { |t| hash[t] += 1 }
p hash
# {"b"=>1, "a"=>3, "n"=>2}
hash.each {|k, v| puts "#{k}は#{v}回"}
# bは1回
# aは3回
# nは2回
tally
- Ruby 2.7 から追加された
tally
を使うと簡単に配列 → ハッシュ
として集計できる
text = "banana"
array = text.chars # ["b", "a", "n", "a", "n", "a"]
hash = array.tally
p hash
# {"b"=>1, "a"=>3, "n"=>2}