【问题标题】:All possible combinations from a hash of arrays in RubyRuby中数组哈希的所有可能组合
【发布时间】: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)

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

【问题讨论】:

    标签: ruby hash combinations


    【解决方案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.
          猜你喜欢
          • 1970-01-01
          • 2014-10-28
          • 2011-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-05-29
          • 2011-07-29
          • 2017-10-04
          相关资源
          最近更新 更多