【问题标题】:Given a hash of arrays, how to create an array of hashes with each possible combo给定一个数组哈希,如何用每个可能的组合创建一个哈希数组
【发布时间】:2018-10-10 20:53:27
【问题描述】:

给定一个哈希值包含长度不等的数组,

{a: [1, 2, 3], b: [1, 2], c: [1]}

是否可以创建一个包含相同键的哈希数组,由单个值的所有排列组成,如下所示,而无需嵌套多个循环?

[
  {a: 1, b: 1, c: 1},
  {a: 1, b: 2, c: 1},
  {a: 2, b: 1, c: 1},
  {a: 2, b: 2, c: 1},
  {a: 3, b: 2, c: 1},
  {a: 3, b: 2, c: 1}
]

我们为每个键使用嵌套的each 循环来实现这一点,但这在大范围内看起来很糟糕。实际数据包含更多键。

【问题讨论】:

  • 第一个问题:你试过什么?提示:combinationzip
  • @tadman zip 不好。如果数组大小不同,则使用以下键压缩每个键的值会产生 nil。这给了我想要的值:hsh[:a].product(hsh[:b]).product(hsh[:c]).map(&:flatten),现在我只需要弄清楚如何做到这一点,而不需要手动获取产品并为每个键展平,并将每个值应用于新哈希数组中的正确键
  • 你说的是排列还是组合?还是你连它们的意思都不知道?

标签: arrays ruby hash


【解决方案1】:
keys = hash.keys
hash.values.inject(:product).map do |p|
  Hash[keys.zip(p.flatten)]
end

【讨论】:

    【解决方案2】:
    h = { a:[1,2,3], b:[1,2], c: [1] }
    
    first, *rest = h.map { |k,v| [k].product(v) }
      #=> [[[:a, 1], [:a, 2], [:a, 3]], [[:b, 1], [:b, 2]], [[:c, 1]]]
    first.product(*rest).map(&:to_h)
      #=> [{:a=>1, :b=>1, :c=>1}, {:a=>1, :b=>2, :c=>1}, {:a=>2, :b=>1, :c=>1},
      #    {:a=>2, :b=>2, :c=>1}, {:a=>3, :b=>1, :c=>1}, {:a=>3, :b=>2, :c=>1}]
    

    注意第二步的中间计算:

    first.product(*rest)
      #=> [[[:a, 1], [:b, 1], [:c, 1]],
      #    [[:a, 1], [:b, 2], [:c, 1]],
      #    [[:a, 2], [:b, 1], [:c, 1]],
      #    [[:a, 2], [:b, 2], [:c, 1]],
      #    [[:a, 3], [:b, 1], [:c, 1]],
      #    [[:a, 3], [:b, 2], [:c, 1]]]
    

    【讨论】:

      【解决方案3】:

      有很多方法可以做到这一点。就个人而言,我喜欢 @Marcin Kołodziej 解决方案的紧凑性和有效性,但是,对于新手来说,它可能看起来有点神秘。

      解决它的另一种方法是手动迭代哈希并构建一个数组:

      hash = { a: [1, 2, 3], b: [1, 2], c: [1] }
      out = []
      
      hash.each do |key, values|
        if out.empty?
          out = values.map { |v| { key => v } }
        else
          new_out = []
          out.each do |o|
            new_out += values.map { |v| o.merge(key => v) }
          end
          out = new_out
        end
      end
      
      out
      
      # [{:a=>1, :b=>1, :c=>1}, {:a=>1, :b=>2, :c=>1}, {:a=>2, :b=>1, :c=>1}, {:a=>2, :b=>2, :c=>1}, {:a=>3, :b=>1, :c=>1}, {:a=>3, :b=>2, :c=>1}] 
      

      【讨论】:

      • 我不是新手,只是面对一堆纠结的遗留意大利面条代码
      猜你喜欢
      • 1970-01-01
      • 2014-04-18
      • 1970-01-01
      • 2011-07-26
      • 2021-11-24
      • 2021-06-24
      • 1970-01-01
      • 2013-01-23
      • 2011-04-22
      相关资源
      最近更新 更多