パラメータの組み合わせを作りたい時にはArray#productを使う
Cassandraのパラメータを色々変えながらデータを取りたいと思った.
が,それ以前にパラメータの組み合わせを作るだけで四苦八苦してしまったので,ここに書いておこうと思う.
Array#product
RubyにはArray#productが用意されていて,Arrayでパラメータ達を扱うのであれば全く問題ない.
[1, 2].product([3, 4]) => [[1, 3], [1, 4], [2, 3], [2, 4]]
※ただし,Ruby 1.8.7以上で.
Hashでproduct
でも,普通はArrayで延々パラメータを連ねたりしない.ここはHashを使いたい.
しかし,Hashを使おうにもproductはなかった.仕方ないので自分で書くことにした.
# 組み合わせをHashのArrayにして返す class Hash if method_defined?(:product) warn "WARNING: Hash#product conflict occurred." else def product keys = self.keys.sort { |x, y| x.to_i <=> y.to_i } self[keys[0]].product(*self.values_at(*keys[1..-1])).map { |*values| alist = keys.zip(*values) Hash[*alist.flatten] } end end end
試してみる
例えば,パラメータaをa1 a2 a3で,パラメータbをb1 b2 b3で,パラメータcをc1 c2 c3で,それぞれの組み合わせがほしい場合.
require 'pp' params = { :a => %w/a1 a2 a3/, :b => %w/b1 b2 b3/, :c => %w/c1 c2 c3/ } pp params.product => [{:c=>"c1", :a=>"a1", :b=>"b1"}, {:c=>"c2", :a=>"a1", :b=>"b1"}, {:c=>"c3", :a=>"a1", :b=>"b1"}, {:c=>"c1", :a=>"a1", :b=>"b2"}, {:c=>"c2", :a=>"a1", :b=>"b2"}, {:c=>"c3", :a=>"a1", :b=>"b2"}, {:c=>"c1", :a=>"a1", :b=>"b3"}, {:c=>"c2", :a=>"a1", :b=>"b3"}, {:c=>"c3", :a=>"a1", :b=>"b3"}, {:c=>"c1", :a=>"a2", :b=>"b1"}, {:c=>"c2", :a=>"a2", :b=>"b1"}, {:c=>"c3", :a=>"a2", :b=>"b1"}, {:c=>"c1", :a=>"a2", :b=>"b2"}, {:c=>"c2", :a=>"a2", :b=>"b2"}, {:c=>"c3", :a=>"a2", :b=>"b2"}, {:c=>"c1", :a=>"a2", :b=>"b3"}, {:c=>"c2", :a=>"a2", :b=>"b3"}, {:c=>"c3", :a=>"a2", :b=>"b3"}, {:c=>"c1", :a=>"a3", :b=>"b1"}, {:c=>"c2", :a=>"a3", :b=>"b1"}, {:c=>"c3", :a=>"a3", :b=>"b1"}, {:c=>"c1", :a=>"a3", :b=>"b2"}, {:c=>"c2", :a=>"a3", :b=>"b2"}, {:c=>"c3", :a=>"a3", :b=>"b2"}, {:c=>"c1", :a=>"a3", :b=>"b3"}, {:c=>"c2", :a=>"a3", :b=>"b3"}, {:c=>"c3", :a=>"a3", :b=>"b3"}]