Search code examples
arraysrubyruby-hash

Adding Hashes from an array


I am trying to create an array/hash from an array of multiple hashes with same keys and an average of values. My array:

[{:amount=>897500, :gross_amount=>897500, :tax=>147500, :hotel_fees=>0, :base_fare=>750000, :currency=>"INR"}, {:amount=>1006500, :gross_amount=>1006500, :tax=>156500, :hotel_fees=>0, :base_fare=>850000, :currency=>"INR"}]

Now I want to return something like this:

{:amount=>952000, :gross_amount=>952000, :tax=>152000, :hotel_fees=>0, :base_fare=>800000, :currency=>"INR"}

where values are the average of values from each hash with same key.

Is there a simple way to do this. I have tried using merge but currency becomes 0 with it.

My attempt:

p[0].merge(p[1]){|k,v1,v2| (v1+v2)/2 unless v1 && v2 == "INR"}

Edit:

Actually my problem didn't end here, so after getting the average I needed to insert the values inside another hash. So I used something like this:

        price_array = offer_values.map do |v| 
          v.inject do |k, v| 
            k.merge!(price: k[:price].merge(v[:price]){|_, a, b| [a, b].flatten })
          end
        end
        price_array.map do |o|
          o[:price] = {}.tap{ |h| o[:price].each {|k, list| h[k] = list.all?{|e| [Fixnum, NilClass].include? e.class} ? list.map(&:to_i).sum/list.size : list.compact.first ; h  } }
        end

Where offer_array is the one with my orginal/first array in separate hashes. This I have tried for with 2 and 3 hashes and it is working.

If you guys have any suggestion on improving the code, It am open.


Solution

  • For two hashes in array you could use inject and merge checking if the value for the both currency keys are Fixnum class, if not, then take the value of currency "INR" in the first hash and use it:

    array = [
      {:amount=>897500,  :gross_amount=>897500,  :tax=>147500, :hotel_fees=>0, :base_fare=>750000, :currency=>"INR"}, 
      {:amount=>1006500, :gross_amount=>1006500, :tax=>156500, :hotel_fees=>0, :base_fare=>850000, :currency=>"INR"}
    ]
    
    p array.inject{|k,v| k.merge(v){|_,a,b| [a,b].all?{|e| e.is_a?(Fixnum)} ? (a+b)/2 : b}}
    # => {:amount=>952000, :gross_amount=>952000, :tax=>152000, :hotel_fees=>0, :base_fare=>800000, :currency=>"INR"}
    

    For two or more hashes in an array you could try with:

    main_array = [
      {:amount=>897500,  :gross_amount=>897500,  :tax=>147500, :hotel_fees=>0, :base_fare=>750000, :currency=>"INR"}, 
      {:amount=>1006500, :gross_amount=>1006500, :tax=>156500, :hotel_fees=>0, :base_fare=>850000, :currency=>"INR"},
      {:amount=>1006500, :gross_amount=>1006500, :tax=>156500, :hotel_fees=>0, :base_fare=>850000, :currency=>"INR"},
    ]
    array_result = main_array.flat_map(&:to_a).group_by(&:first).map do |key, array| 
      { 
        key => (
          result = array.inject(0) do |total, (_, value)| 
            value.is_a?(Fixnum) ? total + value : value
          end 
          result.is_a?(Fixnum) ? result / main_array.size : result 
        ) 
      } 
    end
    p array_result