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

Popular posts from this blog

linux - xterm copying to CLIPBOARD using copy-selection causes automatic updating of CLIPBOARD upon mouse selection -

c++ - qgraphicsview horizontal scrolling always has a vertical delta -