2016-06-12 7 views
-1

私はこのようになりますオブジェクトの配列がありますRubyのチェーン2つの「GROUP_BY」メソッド

[ 
    {day: 'Monday', class: 1, name: 'X'}, 
    {day: 'Monday', class: 2, name: 'Y'}, 
    {day: 'Tuesday', class: 1, name: 'Z'}, 
    {day: 'Monday', class: 1, name: 'T'} 
] 

を私は日によってグループ化したい、その後、クラスによって

groupedArray['Monday'] => {'1' => [{name: 'X'}, {name: 'T'}], '2' => [{name: 'Y'}]} 

、すなわち、私は」これは、[day、class]キーでハッシュを作成します。

これを達成するための方法は、最初にグループ化してから毎日繰り返し、クラス別にグループ化して新しいハッシュにすることですか?所望のハッシュを得る

+0

あなたは 'groupedArray ['Monday'] => {'1' => [{name: 'X'}、{name: 'T'}]、 '2' => [[ {name: 'Y'}]} '?私はdownvotesのアカウントを期待しています。 –

+0

はい、そうです。申し訳ありませんが間違った角かっこに気付かなかった – Dragos

+0

これを行うためのより短い方法があるかどうかを知りたかっただけです。 – Dragos

答えて

2
arr = [ 
    {day: 'Monday', class: 1, name: 'X'}, 
    {day: 'Monday', class: 2, name: 'Y'}, 
    {day: 'Tuesday', class: 1, name: 'Z'}, 
    {day: 'Monday', class: 1, name: 'T'} 
] 

一つの方法は、マージされ、両方のハッシュに存在するキーの値を決定するためにブロックを使用Hash#updateの形を(別名マージ!)を使用することです。ここでは、最初に:dayの値が同じである場合、次にそのようなそれぞれの発生に対して、の値が(同じ値の場合は:dayの場合)2回行われます。

arr.each_with_object({}) { |g,h| 
    h.update(g[:day]=>{ g[:class].to_s=>[{name: g[:name] }] }) { |_,h1,h2| 
    h1.update(h2) { |_,p,q| p+q } } } 
    #=> {"Monday" =>{"1"=>[{:name=>"X"}, {:name=>"T"}], "2"=>[{:name=>"Y"}]}, 
    # "Tuesday"=>{"1"=>[{:name=>"Z"}]}} 

手順は次のとおりです。

enum = arr.each_with_object({}) 
    #=> #<Enumerator: [{:day=>"Monday", :class=>1, :name=>"X"}, 
    #     {:day=>"Monday", :class=>2, :name=>"Y"}, 
    #     {:day=>"Tuesday", :class=>1, :name=>"Z"}, 
    #     {:day=>"Monday", :class=>1, :name=>"T"}]:each_with_object({})> 

我々は、アレイに変換することによって、この列挙子によって生成される値を見ることができます:

enum.to_a 
    #=> [[{:day=>"Monday", :class=>1, :name=>"X"}, {}], 
    # [{:day=>"Monday", :class=>2, :name=>"Y"}, {}], 
    # [{:day=>"Tuesday", :class=>1, :name=>"Z"}, {}], 
    # [{:day=>"Monday", :class=>1, :name=>"T"}, {}]] 

各アレイ内の空のハッシュが構築され、返されるハッシュです。最初は空ですが、enumの各要素が処理されると部分的に形成されます。

enumの最初の要素は(Enumerator#eachによって)ブロックに渡され、ブロック変数が平行割り当て(somtimes 複数割り当てと呼ばれる)を使用して割り当てられている:我々は今、ブロックを実行

g,h = enum.next 
    #=> [{:day=>"Monday", :class=>1, :name=>"X"}, {}] 
g #=> {:day=>"Monday", :class=>1, :name=>"X"} 
h #=> {} 

を計算:

h.update(g[:day]=>{ g[:class].to_s=>[{name: g[:name] }] }) 
    #=> {}.update("Monday"=>{ "1"=>[{name: "X"}] }) 
    #=> {"Monday"=>{"1"=>[{:name=>"X"}]}} 

この操作は、hの更新された値を返しますハッシュがあること構築された。キー"Monday"は、(hは何の鍵を持っていない)ブロック

マージされ、両方のハッシュに存在していなかったので updateの引数

"Monday"=>{ "1"=>[{name: "X"}] } 

{ "Monday"=>{ "1"=>[{name: "X"}] } } 

の省略形であることを

注意

{ |_,h1,h2| h1.update(h2) { |_,p,q| p+q } } } 

は、det "Monday"の値を決定します。

は今enumの次の値がブロックに渡され、ブロック変数が割り当てられていますhが更新されたこと

g,h = enum.next 
    #=> [{:day=>"Monday", :class=>2, :name=>"Y"}, 
    # {"Monday"=>{"1"=>[{:name=>"X"}]}}] 
g #=> {:day=>"Monday", :class=>2, :name=>"Y"} 
h #=> {"Monday"=>{"1"=>[{:name=>"X"}]}} 

注意を。ブロック計算を実行します。

h.update(g[:day]=>{ g[:class].to_s=>[{name: g[:name] }] }) 
    # {"Monday"=>{"1"=>[{:name=>"X"}]}}.update("Monday"=>{ "2"=>[{name: "Y"}] }) 

両方のハッシュをマージすると、「月曜日」のキーが共有されます。そこで我々は「月曜日」のマージされた値を決定するためにブロックを使用する必要があります。

{ |k,h1,h2| h1.update(h2) { |m,p,q| p+q } } } 
    #=> {"1"=>[{:name=>"X"}]}.update("2"=>[{name: "Y"}]) 
    #=> {"1"=>[{:name=>"X"}], "2"=>[{:name=>"Y"}]} 

は、kブロック変数の説明については、updateのためのドキュメントを参照してくださいh1h2updatemため、pq内部の場合はupdateです。 kおよびmは共通鍵の値です。ブロック計算で使われていないので、私はそれらを一般的な例であるアンダースコアに置き換えました。だから今

:二updateはこのブロックがある

{ |_,p,q| p+q } 

ブロックを使用する必要はありませんでしたので、ハッシュh["Monday]はまだ、キー2を持っていなかった

h #=> { "Monday" => { "1"=>[{ :name=>"X" }], "2"=>[{ :name=>"Y"}] } } 

この操作の前にしかし、enumの最後の要素がhにマージされた場合、:day:classの両方の値が2つのha shesがマージされています。

残りの計算は似ています。

+0

未解決の回答ですが、ほとんどの回答があります。 –

関連する問題