【问题标题】:Ruby hash combinationsRuby 哈希组合
【发布时间】:2014-10-28 11:52:36
【问题描述】:

对于电子商务应用程序,我试图将选项的散列(每个选项都有一系列选项)转换为代表这些选项组合的散列数组。例如:

# Input:
{ :color => [ "blue", "grey" ],
  :size  => [ "s", "m", "l" ] }

# Output:
[ { :color => "blue", :size => "s" },
  { :color => "blue", :size => "m" },
  { :color => "blue", :size => "m" },
  { :color => "grey", :size => "s" },
  { :color => "grey", :size => "m" },
  { :color => "grey", :size => "m" } ]

输入可能在其中包含其他选项,每个选项的选项数量不确定,但它只会嵌套 1 级深度。任意

【问题讨论】:

    标签: ruby-on-rails ruby arrays hash combinations


    【解决方案1】:

    上面的一个变体:

    input = { color: [ "blue", "grey" ],
              size:  [ "s", "m", "l" ],
              wt:    [:light, :heavy] }
    
    keys = input.keys
      #=> [:color, :size, :wt]
    values = input.values
      #=> [["blue", "grey"], ["s", "m", "l"], [:light, :heavy]]
    values.shift.product(*values).map { |v| Hash[keys.zip(v)] }
      #=> [{:color=>"blue", :size=>"s", :wt=>:light},
      #    {:color=>"blue", :size=>"s", :wt=>:heavy},
      #    {:color=>"blue", :size=>"m", :wt=>:light},
      #    {:color=>"blue", :size=>"m", :wt=>:heavy},
      #    {:color=>"blue", :size=>"l", :wt=>:light},
      #    {:color=>"blue", :size=>"l", :wt=>:heavy},
      #    {:color=>"grey", :size=>"s", :wt=>:light},
      #    {:color=>"grey", :size=>"s", :wt=>:heavy},
      #    {:color=>"grey", :size=>"m", :wt=>:light},
      #    {:color=>"grey", :size=>"m", :wt=>:heavy},
      #    {:color=>"grey", :size=>"l", :wt=>:light},
      #    {:color=>"grey", :size=>"l", :wt=>:heavy}]
    

    【讨论】:

      【解决方案2】:

      你可以试试:

      ary = input.map {|k,v| [k].product v}
      output = ary.shift.product(*ary).map {|a| Hash[a]}
      

      结果:

      [
        {:color=>"blue", :size=>"s"},
        {:color=>"blue", :size=>"m"},
        {:color=>"blue", :size=>"l"},
        {:color=>"grey", :size=>"s"},
        {:color=>"grey", :size=>"m"},
        {:color=>"grey", :size=>"l"}
      ]
      

      【讨论】:

      • 我认为您的意思是 shift 而不是 unshift (如果没有给出参数,它不会做任何事情)。而在 Ruby 2+ 中的 FWIW,您可以将最后一个 map 替换为 map(&:to_h),因此:ary.shift.product(*ary).map(&:to_h)
      • @Jordan - 我的意思当然是换班,已经很晚了。 :P 感谢您指出这一点。
      • @BroiSatse 这是一个很好的解决方案,尽管它对初学者来说可能有点不透明。我个人认为解构赋值而不是移位更好一点:first, *rest = input.map {|k,v| [k].product v }; output = first.product(*rest).map(&:to_h)。但这只是我。 ;)
      【解决方案3】:

      您基本上是在这里尝试计算组合,这意味着两个级别的迭代以及聚合这些操作的结果:

      input = {:color=>["blue", "grey"], :size=>["s", "m", "l"]}
      
      combinations = input[:color].flat_map do |color|
        input[:size].collect do |size|
          { color: color, size: size }
        end
      end
      
      puts combinations.inspect
      # => [{:color=>"blue", :size=>"s"}, {:color=>"blue", :size=>"m"}, {:color=>"blue", :size=>"l"}, {:color=>"grey", :size=>"s"}, {:color=>"grey", :size=>"m"}, {:color=>"grey", :size=>"l"}]
      

      这里flat_map 派上用场,因为它折叠了内部展开的结果。

      【讨论】:

      • 谢谢。我正在尝试找到一种更通用的方法来执行此操作,它不依赖于输入哈希的键,因为这些将是用户输入
      • @mu-is-too-short 你说得对。同时,当我说“输入可能包含其他选项,每个选项的选择数量不确定”时,我认为这是暗示的。我认为这个解决方案不能很好地处理这种情况。
      【解决方案4】:

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

      require "ocg"
      
      generator = OCG.new(
        :color => %w[blue grey],
        :size  => %w[s m l]
      )
      
      puts generator.next until generator.finished?
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-19
        • 2016-05-28
        • 2016-03-07
        • 1970-01-01
        • 2015-05-07
        • 1970-01-01
        • 2021-02-05
        相关资源
        最近更新 更多