2016-09-07 7 views
1

私はリストを持っており、それらを分離する必要があります。関係がRailsはその値でハッシュ結合する

Question_set has_many questions 
BookVolume has_many questions 
Subject has_many book_volumes 
Publisher has_many subjects 
Section has_many :questions 

今、私は唯一のarrayhashquestionsおよびそれらの相対的なモデルidnameを入れています。

data = [] 
question_set.questions.each do |q| 
    data << {publisher: {id: q.publisher.id, name: q.publisher.name}, subject: {id: q.book_volume.subject.id, name: q.book_volume.subject.name}, volume: {id: q.book_volume_id, name: q.book_volume.name}, chapter: [{id: q.section_id, name: q.section.name}]} 
end 

したがって、dataは、基本的にはしかし

>>data 

[ 
    { 
     :publisher => { 
       :id => 96, 
      :name => "P1" 
     }, 
      :subject => { 
       :id => 233, 
      :name => "S1" 
     }, 
      :volume => { 
       :id => 1136, 
      :name => "V1" 
     }, 
      :chapter => [ 
      { 
        :id => 16155, 
       :name => "C1" 
      } 
     ] 
    }, 
     { 
     :publisher => { 
       :id => 96, 
      :name => "P1" 
     }, 
      :subject => { 
       :id => 233, 
      :name => "S1" 
     }, 
      :volume => { 
       :id => 1136, 
      :name => "V1" 
     }, 
      :chapter => [ 
      { 
        :id => 16158, 
       :name => "C2" 
      } 
     ] 
    } 
] 

だろう、私は彼らが得た場合chapterを組み合わせることにしたい同じpublishersubjectのでvolume 、この場合には、それは次のようになります

>>data 

[ 
    { 
     :publisher => { 
       :id => 96, 
      :name => "P1" 
     }, 
      :subject => { 
       :id => 233, 
      :name => "S1" 
     }, 
      :volume => { 
       :id => 1136, 
      :name => "V1" 
     }, 
      :chapter => [ 
      { 
        :id => 16155, 
       :name => "C2" 
      }, 
      { 
        :id => 16158, 
       :name => "C2" 
      } 
     ] 
    } 
] 

答えて

2

コード

def group_em(data) 
    data.group_by { |h| [h[:publisher], h[:subject], h[:volume]] }. 
     map do |k,v| 
     h = { publisher: k[0], subject: k[1], volume: k[2] } 
     h.update(chapters: v.each_with_object([]) { |f,a| 
      a << f[:chapter] }.flatten) 
     end 
end 

dataは、ハッシュの配列(上記の最初の配列)が等しいです。ここで

group_em(data) 
    #=> [{:publisher=>{:id=>96, :name=>"P1"}, 
    #  :subject=>{:id=>233, :name=>"S1"}, 
    #  :volume=>{:id=>1136, :name=>"V1"}, 
    #  :chapters=>[{:id=>16155, :name=>"C1"}, {:id=>16158, :name=>"C2"}] 
    # } 
    # ] 

dataは2つのハッシュが含まれており、これらのハッシュはキー:publisher:subject:volumeに同じ値を持っています。このコードでは、配列に任意の数のハッシュを持たせることができ、これらの3つのキーの値の配列でグループ化し、それぞれのグループに対して1つのハッシュを生成します。さらに、キー:chaptersの値は1つのハッシュを含む配列ですが、このコードではその配列に複数のハッシュが含まれています。

(その配列は常に:chaptersハッシュそのものではなく、そのハッシュを含む配列の値にすることを検討、正確に1つのハッシュを持つことになります。場合)説明

Enumerable#group_byHash#update(別名Hash#merge!)を参照してください。

手順は次のとおりです。

h = data.group_by { |h| [h[:publisher], h[:subject], h[:volume]] } 
    #=> { 
    # [{:id=>96, :name=>"P1"}, 
    #  {:id=>233, :name=>"S1"}, 
    #  {:id=>1136, :name=>"V1"} 
    # ]=>[{:publisher=>{:id=>96, :name=>"P1"}, 
    #   :subject=>{:id=>233, :name=>"S1"}, 
    #   :volume=>{:id=>1136, :name=>"V1"}, 
    #   :chapter=>[{:id=>16155, :name=>"C1"}] 
    #  }, 
    #  {:publisher=>{:id=>96, :name=>"P1"}, 
    #   :subject=>{:id=>233, :name=>"S1"}, 
    #   :volume=>{:id=>1136, :name=>"V1"}, 
    #   :chapter=>[{:id=>16158, :name=>"C2"}] 
    #  } 
    #  ] 
    # } 

最初のキーと値のペアはmapのブロックに渡され、ブロック変数が割り当てられます。

k,v = h.first 
    #=> [[{:id=>96, :name=>"P1"}, {:id=>233, :name=>"S1"}, {:id=>1136, :name=>"V1"}], 
    # [{:publisher=>{:id=>96, :name=>"P1"}, :subject=>{:id=>233, :name=>"S1"}, 
    #  :volume=>{:id=>1136, :name=>"V1"}, :chapter=>[{:id=>16155, :name=>"C1"}]}, 
    # {:publisher=>{:id=>96, :name=>"P1"}, :subject=>{:id=>233, :name=>"S1"}, 
    #  :volume=>{:id=>1136, :name=>"V1"}, :chapter=>[{:id=>16158, :name=>"C2"}]}]] 
k #=> [{:id=>96, :name=>"P1"}, {:id=>233, :name=>"S1"}, {:id=>1136, :name=>"V1"}] 
v #=> [{:publisher=>{:id=>96, :name=>"P1"}, 
    #  :subject=>{:id=>233, :name=>"S1"}, 
    #  :volume=>{:id=>1136, :name=>"V1"}, 
    #  :chapter=>[{:id=>16155, :name=>"C1"}]}, 
    # {:publisher=>{:id=>96, :name=>"P1"}, 
    #  :subject=>{:id=>233, :name=>"S1"}, 
    #  :volume=>{:id=>1136, :name=>"V1"}, 
    #  :chapter=>[{:id=>16158, :name=>"C2"}]}] 

であり、ブロック計算が行われる。

h = { publisher: k[0], subject: k[1], volume: k[2] } 
    #=> {:publisher=>{:id=>96, :name=>"P1"}, 
    # :subject=>{:id=>233, :name=>"S1"}, 
    # :volume=>{:id=>1136, :name=>"V1"} 
    # } 
a = v.each_with_object([]) { |f,a| a << f[:chapter] } 
    #=> [[{:id=>16155, :name=>"C1"}], [{:id=>16158, :name=>"C2"}]] 
b = a.flatten 
    #=> [{:id=>16155, :name=>"C1"}, {:id=>16158, :name=>"C2"}] 
h.update(chapters: b) 
    #=> {:publisher=>{:id=>96, :name=>"P1"}, 
    # :subject=>{:id=>233, :name=>"S1"}, 
    # :volume=>{:id=>1136, :name=>"V1"}, 
    # :chapters=>[{:id=>16155, :name=>"C1"}, {:id=>16158, :name=>"C2"}] 
    # } 

Hash#mergeHash#updateの代わりに使用することができます。

+0

「arrをハッシュの配列(上記の最初の配列)と同じにすると、次のことができます。「arr = data」を意味しますか? –

+0

変数 'data'がその配列を保持している場合、yesです。例を挙げると、各入力オブジェクトに変数を割り当てると便利です(例えば、 'data = [{:publisher => ...]')。そうすれば、読者は、コメントと回答の変数(ここでは単に「データ」)を定義することなく参照することができます。それを行うためにあなたの質問を編集するかもしれません。 –

+0

私は変数名 'data = []'を定義し、それに私の質問で 'hash'を入れました。これはどういう意味ですか? –

1

方法について:

data = {} 

    question_set.questions.each do |q| 
     key = "#{q.publisher.id}:#{q.book_volume.subject.id}:#{q.book_volume_id}" 
     if data[key].present? 
     data[key][:chapter] << {id: q.section_id, name: q.section.name} 
     else 
     data[key] = {publisher: {id: q.publisher.id, name: q.publisher.name}, subject: {id: q.book_volume.subject.id, name: q.book_volume.subject.name}, volume: {id: q.book_volume_id, name: q.book_volume.name}, chapter: [{id: q.section_id, name: q.section.name}]} 
     end 
    end 

    result = data.values 

使用publisher'id、subject'idの組み合わせや、あなたのデータを結合するためのユニークなキーとしてvolume'id。

+0

私のデータは配列型ですが、多くのハッシュが含まれています。 –

+0

最終行のresult = data.valuesでは、配列になります。 –

+0

ああ、私はそれを見逃して、それは本当に素晴らしいアプローチです! –

関連する問題