ruby on rails - Merge hashes with multiple keys/values -
i have array of hashes of merge hashes contain specific duplicate key value.
combined_keywords = new_array_of_hashes.each_with_object(hash.new(0)){|oh, newh| newh[oh[:keyword]] += oh[:total_value].to_f }
this creates array of hashes this:
{ :actual_keyword => actual_total_value }
i'm new ruby , don't quite understand magic behind this. have additional key , value consolidate , i'm lost. root of issue don't understand how consolidation occurring in line: newh[oh[:keyword]] += oh[:total_value].to_f
i tried no luck:
combined_keywords = new_array_of_hashes.each_with_object(hash.new(0)){|oh, newh| newh[oh[:keyword]] += oh[:total_value].to_f newh[oh[:keyword]] += oh[:revenue_per_transaction].to_f }
i need array of consildated hashes each similar to:
{ :keyword => "actual_keyword", :total_value => actual_total_value, :revenue_per_transaction => actual_revenue }
edit:
input
new_array_of_hashes = [ { keyword: 'foo', total_value: 1, revenue_per_transaction: 5 }, { keyword: 'bar', total_value: 2, revenue_per_transaction: 4 }, { keyword: 'bar', total_value: 4, revenue_per_transaction: 4 }, { keyword: 'foo', total_value: 3, revenue_per_transaction: 5 }, ]
desired output
combined_keywords = [ { keyword: 'foo', total_value: 4, revenue_per_transaction: 10 }, { keyword: 'bar', total_value: 6, revenue_per_transaction: 8 }, ]
let's have:
new_array_of_hashes = [ { keyword: 'foo', total_value: 1 }, { keyword: 'bar', total_value: 2 }, { keyword: 'bar', total_value: 4 }, { keyword: 'foo', total_value: 3 }, ]
now we'll step through code:
combined_keywords = new_array_of_hashes.each_with_object(hash.new(0)){|oh, newh| newh[oh[:keyword]] += oh[:total_value].to_f }
this loop on each hash in array. setup new hash returns 0
if access key doesn't exist:
# pass 1 oh = { keyword: 'foo', total_value: 1 } newh = {} newh[ oh[:keyword] ] #=> newh['foo'] key doesn't exist , returns 0 oh[:total_value].to_f #=> 1.to_f => 1.0 newh[oh[:keyword]] += oh[:total_value].to_f #=> newh['foo'] = newh['foo'] + oh[:total_value].to_f #=> newh['foo'] = 0 + 1.0 # pass 2 oh = { keyword: 'bar', total_value: 2 } newh = { 'foo' => 1.0 } newh[ oh[:keyword] ] #=> newh['bar'] key doesn't exist , returns 0 oh[:total_value].to_f #=> 2.to_f => 2.0 newh[oh[:keyword]] += oh[:total_value].to_f #=> newh['bar'] = newh['bar'] + oh[:total_value].to_f #=> newh['bar'] = 0 + 2.0
now since have keys next 2 iterations access things normal:
# pass 3 oh = { keyword: 'bar', total_value: 4 } newh = { 'foo' => 1.0, 'bar' => 2.0 } newh[ oh[:keyword] ] #=> newh['bar'] key exists , returns 2.0 oh[:total_value].to_f #=> 4.to_f => 4.0 newh[oh[:keyword]] += oh[:total_value].to_f #=> newh['bar'] = newh['bar'] + oh[:total_value].to_f #=> newh['bar'] = 2.0 + 4.0 # pass 4 oh = { keyword: 'foo', total_value: 3 } newh = { 'foo' => 1.0, 'bar' => 6.0 } newh[ oh[:keyword] ] #=> newh['foo'] key exists , returns 1.0 oh[:total_value].to_f #=> 3.to_f => 3.0 newh[oh[:keyword]] += oh[:total_value].to_f #=> newh['foo'] = newh['foo'] + oh[:total_value].to_f #=> newh['foo'] = 1.0 + 3.0
when block returns return newh
; how each_with_object
works.
as can see, returned hash of form:
{ 'foo' => 4.0, 'bar' => 6.0 }
so combined array new key stored :keyword
object, , value sum total.
based on new hash form
{ keyword: "actual_keyword", total_value: actual_total_value, revenue_per_transaction: actual_revenue }
this format won't make sense. since hashes have key:value pairs. may need have hash of sub-hashes, or run through loop twice. once :total_value
, once :revenue_per_transaction
. depend want final object(s) be.
edit:
based on new expected input , output, use:
sum_keys = [:total_value, :revenue_per_transaction] new_array_of_hashes.group_by{ |h| h[:keyword] } .map{ |keyword, related| tmp = {keyword: keyword} tmp.merge! hash[sum_keys.zip array.new(sum_keys.size, 0)] related.reduce(tmp){ |summed, h| sum_keys.each{ |key| summed[key] += h[key] } summed } } #=> [ # { keyword: 'foo', total_value: 4, revenue_per_transaction: 10 }, # { keyword: 'bar', total_value: 6, revenue_per_transaction: 8 }, #]
it's bit messy. i'd refactor map
call doing it's own helper method. reason i'm providing start value reduce
because otherwise mutate original hash new_array_of_hashes
.
Comments
Post a Comment