Ruby多个group_by数组

时间:2017-02-09 11:50:36

标签: ruby hash

我有一个这样的数组:

[{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}, {:a=>"2017-01-02", :b=>"5", :c=>"1"}]

例如,如果我使用键“:a”对数组进行分组,则结果为:

p = y.group_by { |g| g[:a]}

 => {"2017-01-01"=>[{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}], "2017-01-02"=>[{:a=>"2017-01-02", :b=>"5", :c=>"1"}]} 

现在我想为每个“:a”键分组:“b”如:

 => {"2017-01-01"=>["2" => [{:a => "2017-01-01", :b => "2", :c => "1" }], ... }

我该怎么办?提前谢谢。

修改

多组由...... 1°group_by a,2°group_by b结果为1°等。

y.group_by {|g| g[:a]}.map do |k,v|
 [
  k, v.group_by { |d| d[:b] }.map do |p,q|
   [p, q.group_by { |f| f[:c] }]
  end.to_h
 ]
end.to_h  

2 个答案:

答案 0 :(得分:5)

快速回答,使用上面的代码:

y = [{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}, {:a=>"2017-01-02", :b=>"5", :c=>"1"}]
p = y.group_by { |g| g[:a]}
q = p.map {|date, list| [date, list.group_by {|g| g[:b]}]}.to_h

这给出了所需的结果:

q == {
  "2017-01-01" => {
    "2"=> [
      {:a=>"2017-01-01", :b=>"2", :c=>"1"},
      {:a=>"2017-01-01", :b=>"2", :c=>"2"}
    ]
  },
  "2017-01-02" => {
    "5"=> [
      {:a=>"2017-01-02", :b=>"5", :c=>"1"}
    ]
  }
}

如果您正在使用Rails v4.2+ project,使用Hash#transform_values,可以稍微简化将哈希映射到数组列表然后将其转换回哈希(使用to_h)的略微奇怪的模式preg_replace

p.transform_values {|list| list.group_by {|g| g[:b]}}

然而,尽管如此,通常认为操作这样的复杂嵌套哈希对象是不好的做法。如果您的代码过于复杂,您可能希望以更加面向对象的方式考虑重新设计它的工作方式。

答案 1 :(得分:2)

我认为,一些可能的解决方案是:

 y = [
  {
    :a=>"2017-01-01", 
    :b=>"2", 
    :c=>"1"
  }, 
  {
    :a=>"2017-01-01", 
    :b=>"2", 
    :c=>"2"
  }, 
  {
    :a=>"2017-01-02", 
    :b=>"5", 
    :c=>"1"
  }
]

第一

y.group_by { |g| [g[:a], g[:b]] }

但结果似乎是:

#=> {["2017-01-01", "2"]=>[{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}], ["2017-01-02", "5"]=>[{:a=>"2017-01-02", :b=>"5", :c=>"1"}]}

和第二个:

y.group_by { |g| g[:a] }.map do |key, value| 
   [key, value.group_by { |g| g[:b] }] 
end.to_h

#=> {"2017-01-01"=>{"2"=>[{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}]}, "2017-01-02"=>{"5"=>[{:a=>"2017-01-02", :b=>"5", :c=>"1"}]}}