Ruby中数组哈希的所有可能组合

时间:2012-03-20 11:54:57

标签: ruby hash combinations

我拥有的是什么:

假设我有这样的哈希值,各种值属于一个参数。

a = {}
a[:bitrate] = ["100", "500", "1000"]
a[:fps] = ["15", "30"]
a[:qp] = ["20", "30"]

我需要什么:

我需要一些方法来迭代地获得所有这些值的可能组合,因此,所有参数/值对:

  • bitrate = 100fps = 15qp = 20
  • bitrate = 500fps = 15qp = 30
  • ...

预先不知道参数(即键)的数量和值的数量(即值阵列的长度)。理想情况下,我会做类似的事情:

a.foo do |ret|
  puts ret.keys   # => ["bitrate", "fps", "qp"]
  puts ret.values # => ["100", "15", "20"]
end

...为每个可能的组合调用块。如何定义foo


我(可能)不需要的东西:

现在,我知道这一点:Combine array of array into all possible combinations, forward only, in Ruby,建议像:

a.first.product(*a[1..-1]).map(&:join)

但是这只对数组中的值和数组进行操作,我需要对参数名称的原始引用。

4 个答案:

答案 0 :(得分:29)

a = {}
a[:bitrate] = ["100", "500", "1000"]
a[:fps] = ["15", "30"]
a[:qp] = ["20", "30"]

def product_hash(hsh)
  attrs   = hsh.values
  keys    = hsh.keys
  product = attrs[0].product(*attrs[1..-1])
  product.map{ |p| Hash[keys.zip p] }
end

product_hash(a)

你会得到

[{:bitrate=>"100", :fps=>"15", :qp=>"20"},
 {:bitrate=>"100", :fps=>"15", :qp=>"30"},
 {:bitrate=>"100", :fps=>"30", :qp=>"20"},
 {:bitrate=>"100", :fps=>"30", :qp=>"30"},
 {:bitrate=>"500", :fps=>"15", :qp=>"20"},
 {:bitrate=>"500", :fps=>"15", :qp=>"30"},
 {:bitrate=>"500", :fps=>"30", :qp=>"20"},
 {:bitrate=>"500", :fps=>"30", :qp=>"30"},
 {:bitrate=>"1000", :fps=>"15", :qp=>"20"},
 {:bitrate=>"1000", :fps=>"15", :qp=>"30"},
 {:bitrate=>"1000", :fps=>"30", :qp=>"20"},
 {:bitrate=>"1000", :fps=>"30", :qp=>"30"}]

您还可以向哈希添加新密钥。

a = {}
a[:bitrate] = ["100", "500", "1000"]
a[:fps] = ["15", "30"]
a[:qp] = ["20", "30"]
a[:bw] = [true, false]

product_hash(a)

#=>
[{:bitrate=>"100", :fps=>"15", :qp=>"20", :bw=>true},
 {:bitrate=>"100", :fps=>"15", :qp=>"20", :bw=>false},
 {:bitrate=>"100", :fps=>"15", :qp=>"30", :bw=>true},
 {:bitrate=>"100", :fps=>"15", :qp=>"30", :bw=>false},
 {:bitrate=>"100", :fps=>"30", :qp=>"20", :bw=>true},
 {:bitrate=>"100", :fps=>"30", :qp=>"20", :bw=>false},
 {:bitrate=>"100", :fps=>"30", :qp=>"30", :bw=>true},
 {:bitrate=>"100", :fps=>"30", :qp=>"30", :bw=>false},
 {:bitrate=>"500", :fps=>"15", :qp=>"20", :bw=>true},
 {:bitrate=>"500", :fps=>"15", :qp=>"20", :bw=>false},
 {:bitrate=>"500", :fps=>"15", :qp=>"30", :bw=>true},
 {:bitrate=>"500", :fps=>"15", :qp=>"30", :bw=>false},
 {:bitrate=>"500", :fps=>"30", :qp=>"20", :bw=>true},
 {:bitrate=>"500", :fps=>"30", :qp=>"20", :bw=>false},
 {:bitrate=>"500", :fps=>"30", :qp=>"30", :bw=>true},
 {:bitrate=>"500", :fps=>"30", :qp=>"30", :bw=>false},
 {:bitrate=>"1000", :fps=>"15", :qp=>"20", :bw=>true},
 {:bitrate=>"1000", :fps=>"15", :qp=>"20", :bw=>false},
 {:bitrate=>"1000", :fps=>"15", :qp=>"30", :bw=>true},
 {:bitrate=>"1000", :fps=>"15", :qp=>"30", :bw=>false},
 {:bitrate=>"1000", :fps=>"30", :qp=>"20", :bw=>true},
 {:bitrate=>"1000", :fps=>"30", :qp=>"20", :bw=>false},
 {:bitrate=>"1000", :fps=>"30", :qp=>"30", :bw=>true},
 {:bitrate=>"1000", :fps=>"30", :qp=>"30", :bw=>false}]

答案 1 :(得分:2)

仅供参考我采用了fl00r的方法并对其进行了修补。我喜欢它好一点。

class Hash
  def product
    product = values[0].product(*values[1..-1])
    product.map{|p| Hash[keys.zip p]}
  end
end

答案 2 :(得分:1)

请尝试使用OCG选项组合生成器。

require "ocg"

generator = OCG.new(
  :bitrate => %w[100 500 1000],
  :fps => %w[15 30],
  :qp => %w[20 30]
)

puts generator.next until generator.finished?

Generator包含更多功能,可帮助您处理其他选项。

答案 3 :(得分:0)

我相信fl00r的答案几乎是完美的但有一个缺点。它假定hsh.valueshsh.keys将有匹配的订单,据我所知,这是不保证的。因此,您可能需要额外的步骤来确保这一点。也许是这样的:

def product_hash(hsh)
  keys  = hsh.keys
  attrs = keys.map { |key| hsh[key] }
  product = attrs[0].product(*attrs[1..-1])
  product.map{ |p| Hash[keys.zip p] }
end

但如果我错了,fl00r可以纠正我。