How to Merge Two Hashes That Have Same Keys in Ruby

How to merge two hashes that have same keys in ruby

Use Hash#merge or Hash#merge!:

a = {a: 1, b: 2, c: 3}
b = {a: 2, c: 4, b: 3}
a.merge!(b) { |k, o, n| o + n }
a # => {:a=>3, :b=>5, :c=>7}

The block is called with key, old value, new value. And the return value of the block is used as a new value.

How to merge array of hash based on the same keys in ruby?

Try

a.flat_map(&:entries)
.group_by(&:first)
.map{|k,v| Hash[k, v.map(&:last)]}

Rails: How to merge two hashes if a specific key has the same value?

The following code would work for your given example.

code

result = arr.group_by {|h| h[:id]}.values.map do |arr|
arr.reduce do |h1, h2|
h1.merge(h2) do |k, ov, nv|
ov.eql?(nv) ? ov : [ov, nv].join(",")
end
end
end

p result

#=>[{:id=>77, :member_phone=>"9876543210,123456789", :created_at=>"2017-05-03T11:06:03.000Z", :name=>"Sure"}, {:id=>78, :member_phone=>"12345", :created_at=>"2017-05-03T11:06:03.000Z", :name=>"XYZ"}]

Combine 2 hashes with the same key

First, I think by {"12 am"=> 0, 0} you mean a Hash with each of its keys being an hour and each value an Array with two elements, one representing the number of cleans in that hour and the other the number of lubes. If that's the case it should be like this: {"12 am"=> [0, 0]} (with [ and ] around each value)

You can do that with something like this:

@count_by_hour = @clean_by_hour.keys.each_with_object({}) do |k, h|
h[k] = [@clean_by_hour[k], @lube_by_hour[k]]
end

@count_by_hour # =>
{"12 am"=>[0, 0],
"1 am"=>[0, 0],
"2 am"=>[0, 0],
"3 am"=>[0, 0],
"4 am"=>[0, 0],
"5 am"=>[0, 0],
"6 am"=>[0, 0],
"7 am"=>[0, 0],
"8 am"=>[4, 3],
"9 am"=>[14, 4],
"10 am"=>[19, 10],
"11 am"=>[10, 14],
"12 pm"=>[19, 10],
"1 pm"=>[16, 8],
"2 pm"=>[13, 5],
"3 pm"=>[18, 20],
"4 pm"=>[7, 4],
"5 pm"=>[4, 2],
"6 pm"=>[4, 0],
"7 pm"=>[0, 0],
"8 pm"=>[0, 0],
"9 pm"=>[0, 0],
"10 pm"=>[0, 0],
"11 pm"=>[0, 0]}

You could also use a Hash for each value to improve the readability and prevent bugs: (It's easier to remember which Hash key to use than which Array index.)

@count_by_hour = @clean_by_hour.keys.each_with_object({}) do |k, h|
h[k] = { clean: @clean_by_hour[k], lube: @lube_by_hour[k] }
end

@count_by_hour # =>
{"12 am"=>{:clean=>0, :lube=>0},
"1 am"=>{:clean=>0, :lube=>0},
"2 am"=>{:clean=>0, :lube=>0},
"3 am"=>{:clean=>0, :lube=>0},
"4 am"=>{:clean=>0, :lube=>0},
"5 am"=>{:clean=>0, :lube=>0},
"6 am"=>{:clean=>0, :lube=>0},
"7 am"=>{:clean=>0, :lube=>0},
"8 am"=>{:clean=>4, :lube=>3},
"9 am"=>{:clean=>14, :lube=>4},
"10 am"=>{:clean=>19, :lube=>10},
"11 am"=>{:clean=>10, :lube=>14},
"12 pm"=>{:clean=>19, :lube=>10},
"1 pm"=>{:clean=>16, :lube=>8},
"2 pm"=>{:clean=>13, :lube=>5},
"3 pm"=>{:clean=>18, :lube=>20},
"4 pm"=>{:clean=>7, :lube=>4},
"5 pm"=>{:clean=>4, :lube=>2},
"6 pm"=>{:clean=>4, :lube=>0},
"7 pm"=>{:clean=>0, :lube=>0},
"8 pm"=>{:clean=>0, :lube=>0},
"9 pm"=>{:clean=>0, :lube=>0},
"10 pm"=>{:clean=>0, :lube=>0},
"11 pm"=>{:clean=>0, :lube=>0}}

Combining two hashes with a common key

What about:

h1 = { "a" => 10, "b" => 20, "c"=>34, "d"=>3} 
h2 = { "a" => 11, "b" => 21, "d"=>15}

p h1.merge(h2){|key, old, new| Array(old).push(new) } #=> {"a"=>[10, 11], "b"=>[20, 21], "c"=>34, "d"=>[3, 15]}

And this is how I would write it to combine more than 2 Hashes:

h1 = { "a" => 10, "b" => 20, "c"=>34, "d"=>3} 
h2 = { "a" => 11, "b" => 21, "d"=>15}
h3 = { "a" => 11, "b" => 21, "c"=> 1, "d"=>15}

merge_to_array = -> x,y { x.merge(y){|key, old, new| Array(old).push(new)} }

p [h1,h2,h3].reduce &merge_to_array #=> {"a"=>[10, 11, 11], "b"=>[20, 21, 21], "c"=>[34, 1], "d"=>[3, 15, 15]}

How can I merge two hashes without overwritten duplicate keys in Ruby?

If you have two hashes, options and defaults, and you want to merge defaults into options without overwriting existing keys, what you really want to do is the reverse: merge options into defaults:

options = defaults.merge(options)

Or, if you're using Rails you can do:

options.reverse_merge!(defaults)

How to merge two hashes with same ID by combining keys with different values

hashes.
group_by { |e| [e[:id], e[:value]] }.
map { |_, g|
g.first.clone.
tap { |t|
t[:source] = g.reduce([]) { |a, e| a << e[:source] }
}
}

First group the hashes by the part that should be the same. We don't care about the key any more; but each group itself will map to something very similar to the first element of the group. Clone it so the original hashes elements are not mutated; then replace its :source with the accumulation of all the group's elements' :source values.

Merge Ruby Hash values with same key

I can't see a simpler version of your code. To make it fully work, you can use the first argument in the merge block instead of dismissing it to differentiate when you need to merge a and b or when you just use a. Your line becomes:

s.merge(l) { |key, a, b| key == :a ? a : [a, b].uniq.join(", ") }


Related Topics



Leave a reply



Submit