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

Posted

技术标签:

【中文标题】Ruby中数组哈希的所有可能组合【英文标题】:All possible combinations from a hash of arrays in Ruby 【发布时间】:2012-04-04 21:19:14 【问题描述】:

我有什么:

假设我有一个像这样的散列,不同的值属于一个参数。

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

我需要什么:

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

bitrate = 100, fps = 15, qp = 20 bitrate = 500, fps = 15, qp = 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)

但这仅对数组中的值和数组起作用,我需要对参数名称的原始引用。

【问题讨论】:

【参考方案1】:
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]

【讨论】:

【参考方案2】:

仅供参考,我采用了 fl00r 的方法并对其进行了猴子修补。我更喜欢它。

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

【讨论】:

【参考方案3】:

请尝试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?

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

【讨论】:

【参考方案4】:

我相信 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 可以纠正我。

【讨论】:

对于 Ruby >= 1.9,它们的顺序相同 这是由语言规范或仅适用于 MRI 的东西所保证的吗?在这两种情况下,您能否请我指出确保这一点的文档?我永远不知道在哪里可以找到这样的东西。谢谢。 ruby-doc.org/core-2.4.1/Hash.html Hashes enumerate their values in the order that the corresponding keys were inserted.

以上是关于Ruby中数组哈希的所有可能组合的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ruby 中使用循环输出所有可能的组合?

ruby 在RSpec中使用哈希来检查不同的变量/值组合

ruby 在RSpec中使用哈希来检查不同的变量/值组合

从Ruby中的列表中获取所有对的组合

打印出数组数组中元素的所有组合[重复]

获取数组中所有可能的字符组合