HashのArray

んでこの話。

data = [
  {'name'=>'Foo', 'age'=>20, 'email'=>'foo@mail.com'},
  {'name'=>'Bar', 'age'=>21, 'email'=>'bar@mail.net'},
  {'name'=>'Baz', 'age'=>22, 'email'=>'baz@mail.org'},
]

これを、

data = %h{
  ['name', 'age', 'email'],
  ['Foo',   20,   'foo@mail.com'],
  ['Bar',   21,   'bar@mail.net'],
  ['Baz',   22,   'baz@mail.org'],
}

こう書きたいという話が。

えぇ…。標準でいるかな、コレ?
第一最初のArrayだけ特別扱いなのが気に食わない。自分で書いて使うならともかく…。
というかちょっと面倒臭がらなければほとんど似たようなもんが書けないか?

keys = %w[name age email]
data = [
  ['Foo',   20,   'foo@mail.com'],
  ['Bar',   21,   'bar@mail.net'],
  ['Baz',   22,   'baz@mail.org'],
].map{|vals|
  h = {}
  keys.zip(vals){|k, v| h[k] = v }
  h
}

これぐらいでも「めんどくさくてイヤ」って言われてしまうのだろうか。
メソッドで抽象化するなら、

def hash_list(*keys)
  yield.map{|vals|
    h = {}
    keys.zip(vals){|k, v| h[k] = v }
    h
  }
end

data = hash_list('name', 'age', 'email'){[
  ['Foo',   20,   'foo@mail.com'],
  ['Bar',   21,   'bar@mail.net'],
  ['Baz',   22,   'baz@mail.org'],
]}

見た目的にはわりと良くない?

ところで、

h = {}
keys.zip(vals){|k, v| h[k] = v }
h

どっちにもこういうのが出てきた。つまりalistからHashへの変換を抽象化するものが標準であれば、メソッドにしなくても

keys = %w[name age email]
data = [
  ['Foo',   20,   'foo@mail.com'],
  ['Bar',   21,   'bar@mail.net'],
  ['Baz',   22,   'baz@mail.org'],
].map{|vals| keys.zip(vals).alist_to_hash }

おお。大分良くないか。
Rubyの変化を追えてないからわかんないけど、増えてないかな? 1.9とかで。
1.8にもバックポートされてる新メソッドはたくさんあるんだよね。

欲しいなー。可変引数とか多重代入とか、Arrayでしゃばりすぎな感もあるけど、Array#assocとかArray#rassocとかあるんだから、この際Array#assoc_to_hashとかだめ?


とりあえずそれがあれば自分は%h記法はいらないかな。抽象化は再利用し易いレベルで機能を切り分けてやってもらえたほうが嬉しい。


追記:
rubikitchさんがStructを使った方法を述べていらっしゃった。なるほど。

[ruby]そこでStructですよ
http://d.hatena.ne.jp/rubikitch/20080428/1209352827

そーだよ、なんでもHashにしたがるから駄目なんだよ。Struct使おうよ。[]でもアクセスできるよ?(<-思いつかなかった癖に)

キーが同じHashがいくつも続くのが嫌なら、そのデータ構造をまず抽象化しとけよ、っていうもやもやがやっと言葉にできた。Struct使うと宣言的で分かり易いなぁ。