Ruby: Merge Two Hash as One and with Value Connected

Ruby: merge two hash as one and with value connected

h = h1.merge(h2){|key, first, second| first + " " + second }

It will work if your keys are the same. In your code, they aren't ("s1" vs "s1="). Are they supposed to be the same keys?

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.

ruby merge two hash by same key and same values

Use Hash#merge

a = {:ip=>"192.168.2.1", :b=>2}
b = {:ip=>"192.168.2.1", :c=>4}
newhash = a.merge(b)
#=> {:ip=>"192.168.2.1", :b=>2, :c=>4}

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"}]

Merge two hash arrays into one without changing Key value pairs in Ruby

Your question is still very confusing. I am assuming that you have this input:

a = [{"name" => "rihan"}, {"name" => "gihan"}, {"name" => "mihan"}]
b = [{"value" => 1}, {"value" => 2}, {"value" => 3}]

And you desire this output:

[{"name"=>"rihan", "value"=>1},
{"name"=>"gihan", "value"=>2},
{"name"=>"mihan", "value"=>3}]

Which can be achieved with:

a.zip(b).map { |ar| ar.inject(:merge) }

Or in this specific case (where the arrays after zipping are always 2-element):

a.zip(b).map { |x,y| x.merge(y) }

As

a.zip(b) #=> [[{"name"=>"rihan"}, {"value"=>1}], [{"name"=>"gihan"}, {"value"=>2}], [{"name"=>"mihan"}, {"value"=>3}]]

And then each element of the array is mapped by merging all of its elements.

Or a bit more explicit version, with a simple loop:

a.size.times.with_object([]) do |i, output|
output << a[i].merge(b[i])
end

In ruby how can we merge two given hash into single hash and replace duplicate key value with greater of both the value

hash1 = { "a" => "123", "b" => "432" }

hash2 = { "a" => "439", "c" => "987" }

Code

h = hash1.merge(hash2) do |k, f, s|
f.to_i > s.to_i ? f : s
end
p h

Output

{"a"=>"439", "b"=>"432", "c"=>"987"}

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}}

Merge and Combine Hash Values in an Array

As others have commented, you need to show what you actually expect your output to be but I think I understand what you are looking for.

Here is a hash that I think matches the format of your hash.

my_hash = {key1: [:key1_value1, :key1_value2],key2: [:key2_value1, :key2_value2], key3: [:key3_value1, :key3_value2]} 

To merge all the values just get the values, which will be a array of 2 element arrays, and then flatten that in to an single array.

my_hash.values.flatten

returns:

[:key1_value1, :key1_value2, :key2_value1, :key2_value2, :key3_value1, :key3_value2]

If you want to retain the value pairs, then just don't flatten the values.

my_hash.values

returns:

[[:key1_value1, :key1_value2], [:key2_value1, :key2_value2], [:key3_value1, :key3_value2]] 

If you only want to select a subset of the entries in your has you can do something like this:

my_hash.select {|k,v| [:key1, :key2].include? k}.values.flatten

which returns:

[:key1_value1, :key1_value2, :key2_value1, :key2_value2]

The reason the following did not work is because as you saw the first select only returns the entry matching 'Apple_HLS(Media)' the second select is applied to the result of the first select which no longer includes the entry for 'Apple_HLS_Prev(Media)'

outputs['output_files'] = inputs['output_files_hash'].select{ |k,v| k == 'Apple_HLS(Media)' }.select{ |k,v| k == 'Apple_HLS_Prev(Media)' }.values

While I think what I posted (using the array include? method) above is cleaner, you might get what you want by saying the key should be Apple_HLS(Media) OR Apple_HLS_Prev(Media)

outputs['output_files'] = inputs['output_files_hash'].select{ |k,v| k == 'Apple_HLS(Media)' || k == 'Apple_HLS_Prev(Media)'}.values

but I think this is cleaner:

outputs['output_files'] = inputs['output_files_hash'].select { |k,v| ['Apple_HLS(Media)', 'Apple_HLS_Prev(Media)'].include? k }.values

How to merge two hashes without losing values

if the format of your hash would always look like you specified the below would work:

a = {foo: {first: 1}, bar: {first: 2}}
b = {foo: {second: 3}, bar: {second: 4}}
a.each_with_object(b) { |(k,v),x| x[k].merge!(v) }
# => {:foo=>{:second=>3, :first=>1}, :bar=>{:second=>4, :first=>2}}

Otherwise use ActiveSupport's deep_merge!

Ruby - Merge two hashes and maintain ordered keys

(a.values + b.values).uniq.map.with_index{|v, i| [i.to_s, v]}.to_h
# => {"0"=>"name", "1"=>"email", "2"=>"source", "3"=>"info", "4"=>"extra"}


Related Topics



Leave a reply



Submit