dreamedge.net

ArrayをHashに変換する

2008-08-24T12:02:00+0000

マニュアルのHashのページに同様の内容があるのだけど,ちょっと分かりづらかったのでエラーを出す事例とかも含めてまとめ直してみた.

前提:一般的なハッシュの作り方

h = {1=>'a', 2=>'b', 3=>'c'}
h = {1, 'a', 2, 'b', 3, 'c'}
h = Hash[1=>'a', 2=>'b', 3=>'c']
h = Hash[1, 'a', 2, 'b', 3, 'c']
#=> {1=>"a", 2=>"b", 3=>"c"}

一般的には一番上しか使わないと思うけど,この4通りがどれも同じハッシュを作る.ArrayからHashに変換するときは一番下のパターンを使うので,ここを覚えておいてください.

基本編:[キー, 値, …] の配列からハッシュへ変換する

多重代入の説明時に書いた,’*’を用いた配列の展開を用いてHashを作る.

a = [1,"a", 2,"b", 3,"c"]
h = Hash[*a]
#=> {1=>"a", 2=>"b", 3=>"c"}

入力側が偶数個でないとエラーになる.

a = [1,"a", 2,"b", 3]
h = Hash[*a]
#=> ArgumentError: odd number of arguments for Hash

カギカッコでの作成もエラーになる.(多重代入としての処理がされないためだと思う)

a = [1,"a", 2,"b", 3,"c"]
h = {*a}
#=> SyntaxError: compile error

基本編2:キーと値のペアの配列からハッシュへ

普通は[[キー, 値], [キー, 値], …]っていう2重配列にすると思う.その形式からはflattenを使う.

a = [[1,"a"], [2,"b"], [3,"c"]]
h = Hash[*a.flatten]
#=> {1=>"a", 2=>"b", 3=>"c"}

ちなみにハッシュを配列に変換するto_aメソッドは2重配列を返す仕様.きわめてややこしいというか,何で非対称な作りになっているんだか理解できない.

h = {1=>"a", 2=>"b", 3=>"c"}
a = h.to_a
#=> [[1, "a"], [2, "b"], [3, "c"]]

応用編:キーと値の配列のペアからハッシュへ

キーの集合と値の集合が別個の配列になっている場合は,zipやtranposeで結合してから変換する.

keys = [1, 2, 3]
vals = ["a", "b", "c"]
a = keys.zip(vals)
#もしくは a = [keys,vals].transpose
h = Hash[*a.flatten]
#=> {1=>"a", 2=>"b", 3=>"c"}

keysとvalsの長さが違う場合,transposeはエラーを出す.一方zipは呼び出し元に揃えるので,状況に応じて使い分けると良い.

a1 = [ 1 ,  2 , 3]
a2 = ['a', 'b']
a1.zip(a2)
#=> [[1, "a"], [2, "b"], [3, nil]]
a2.zip(a1)
#=> [["a", 1], ["b", 2]]
[a1,a2].transpose
#=> IndexError: element size differs (2 should be 3)