2017-04-01 22 views
0

キー値参照を含むオブジェクトの配列があります。Rails - 別々のオブジェクトに値を追加する方法

私がしたい
[{booking_ref: 'w578383', foo: 'bar', price1: 500, price2: 30], 
{booking_ref: 'w578383', foo: 'bar', price1: 600, price2: 40}, 
{booking_ref: 'r123523', foo: 'bar', price1: 699, price2: 4}] 

:キーと値の参照(booking_ref)

  • によって

    • グループオブジェクトがへprice1とprice2(これらのグループを通過し、各オブジェクトにのみ一緒に財務数値を追加他の予約のprice1とprice2)
    • グループからの崩壊キー値参照を含むオブジェクトの配列に戻る。それは今のようになります。

      [{booking_ref: 'w578383', foo: 'bar', price1: 1100, price2: 70}, 
      {booking_ref: 'r123523', foo: 'bar', price1: 699, price2: 4}] 
      

    私は思っています:

    objects.group_by(&:booking_ref).each {|group| 
        group.merge {|key, value1, value2| value1 + value2 if key == price1 || price2} 
    } 
    

    がその作業を行うので、場合どのように私は、その後GROUP_BY状態から戻ってそれらを返すのですか?ハッシュオブジェクトと

  • 答えて

    1

    。他の人はgroup_byを使っているので、ここではハッシュマージの答えを示します。

    変数bookingsをハッシュの配列と同じにすると、次のように書くことができます。

    keys_to_aggregate = [:price1, :price2] 
    
    bookings.each_with_object({}) { |g,h| h.update(g[:booking_ref]=>g) { |_,o,n| 
        keys_to_aggregate.reduce(o) { |f,k| f.merge(k=>o[k] + n[k]) } } }.values 
        #=> [{:booking_ref=>"w578383", :foo=>"bar", :price1=>1100, :price2=>70}, 
        # {:booking_ref=>"r123523", :foo=>"bar", :price1=>699, :price2=>4}] 
    

    式の最後のHash#valuesが評価される前に、次のことがあります。

    bookings.each_with_object({}) { |g,h| h.update(g[:booking_ref]=>g) { |_,o,n| 
        keys_to_aggregate.reduce(o) { |f,k| f.merge(k=>o[k] + n[k]) } } } 
        #=> {"w578383"=>{:booking_ref=>"w578383", :foo=>"bar", :price1=>1100, :price2=>70}, 
        # "r123523"=>{:booking_ref=>"r123523", :foo=>"bar", :price1=>699, :price2=>4}} 
    

    これは、マージされ、両方のハッシュに存在するキーの値を決定するためにブロックを使用Hash#updateの形態を使用します。詳細については、特に値決定ブロックの3つの変数(k,oおよびn)の定義についてのドキュメントを参照してください。 (ブロック計算で使用されていないことを意味するk [the key]を_に置き換えました)

    +0

    それは感謝します! 1つの方法は、1つの長い行に各価格をリストする必要からそれをリファクタリングする方法です。実際には合併する必要がある5/6の価格があります。 – JamesJY

    +1

    私はそれに対処する方法を変更しました。 –

    +0

    @ JamesJY:このコードがあなたのデータ構造に対してうまく動作する場合、なぜ私のコードでうまくいかないのか理解できません。とにかく、あなたは通常、ケアリーの答えに間違って行くことはできません。 –

    1

    、あなたは合計を計算し、各グループの最初のハッシュに戻ってそれらをマージすることができます:

    bookings = [ 
    {booking_ref: 'w578383', foo: 'bar', price1: 500, price2: 30}, 
    {booking_ref: 'w578383', foo: 'bar', price1: 600, price2: 40}, 
    {booking_ref: 'r123523', foo: 'bar', price1: 699, price2: 4} 
    ] 
    
    grouped_bookings = bookings.group_by{ |h| h[:booking_ref] }.map do |ref, hs| 
        sums = hs.each_with_object(Hash.new(0)) do |h, sum| 
        %i(price1 price2).each do |price| 
         sum[price] += h[price].to_i 
        end 
        end 
        hs.first.merge(sums) 
    end 
    
    p grouped_bookings 
    # [{:booking_ref=>"w578383", :foo=>"bar", :price1=>1100, :price2=>70}, 
    # {:booking_ref=>"r123523", :foo=>"bar", :price1=>699, :price2=>4}] 
    
    +0

    @JamesJY:はい、私のオブジェクトはハッシュであり、おそらくあなたのものではありません。あなたはオブジェクト定義を含まなかったので、ハッシュを使用しなければなりませんでした。 'hash [:key]'呼び出しを 'object.key'メソッド呼び出しで置き換えることができます。 –

    +0

    @JamesJY:あなたのオブジェクトを初期化するコードで質問を更新してください。 –

    +0

    これらのオブジェクトが何であるかはまだ明らかではありません。彼らはハッシュのように見えるが、明らかにそうではない。彼らのクラスは何ですか? –

    0

    まず、group_byは結構です、そして、ハッシュを反復して、削減にmapを使用ここでは、オブジェクト指向のアプローチを取るinject

    objects.group_by(&:booking_ref) 
         .map{|ref, list| {booking_ref: ref, 
             price1: => list.inject(0){|sum,h| sum + h.price1}, 
             price2: => list.inject(0){|sum,h| sum + h.price2} 
             } 
          } 
    
    +1

    閉じるが、バナナはありません。誰かがテストしなかった... –

    0

    使用合計にリストから値は、あなたが、これはかなりきちんとしたエレガントな探して取得することができます。重要な点は、オブジェクトに対して+メソッドを定義することです。以下の完全な例:あなたはHash#mergeまたはHash#update(別名merge!)のいくつかのフォームを使用し、その逆も可能Enumerable#group_byを使用することができますたび

    class Booking 
        attr_accessor :booking_ref, :foo, :price1, :price2 
    
        def initialize(params={}) 
        params.each { |key, value| send "#{key}=", value } 
        end 
    
        # add up prices, and return new Booking object 
        def +(other) 
        new_obj = self.dup 
        new_obj.price1 += other.price1 
        new_obj.price2 += other.price2 
        new_obj 
        end 
    end 
    
    # set up example bookings 
    bookings = [ 
        Booking.new(booking_ref: 'w578383', foo: 'bar', price1: 500, price2: 30), 
        Booking.new(booking_ref: 'w578383', foo: 'bar', price1: 600, price2: 40), 
        Booking.new(booking_ref: 'r123523', foo: 'bar', price1: 699, price2: 4) 
    ] 
    
    
    # grouping becomes very simple - potentially a one-liner 
    bookings.group_by(&:booking_ref).map { |_, values| values.reduce(&:+) } 
    # => [ 
         #<Booking:... @booking_ref="w578383", @foo="bar", @price1=1100, @price2=70>, 
         #<Booking:... @booking_ref="r123523", @foo="bar", @price1=699, @price2=4> 
        ] 
    
    関連する問題