Help with Hash_My_Merge

class Hash

Hash#merge takes a proc that accepts three arguments: a key and the two

corresponding values in the hashes being merged. Hash#merge then sets that

key to the return value of the proc in a new hash. If no proc is given,

Hash#merge simply merges the two hashes.

Write a method with the functionality of Hash#merge. Your Hash#my_merge method

should optionally take a proc as an argument and return a new hash. If a proc

is not given, your method should provide default merging behavior. Do not use

Hash#merge in your method.

def my_merge(hash, &prc)
prc ||= Proc.new { |k, oldval, newval| newval }
new_hash = {}

self.each do |key, value|
  new_hash[key] =  hash[key] ? prc.call(key, value, hash[key]) : value
end

hash.each do |key, value|
  new_hash[key] = value if new_hash[key].nil?
end

new_hash

end

end

end

I got error:Failures:

  1. Hash#my_merge yields each element to the block
    Failure/Error: expect { |b| test_hash_1.my_merge(test_hash_2, &b)}.to yield_successive_args([:b, 2, 3])

    expected given block to yield successively with arguments, but yielded with unexpected arguments
    expected: [[:b, 2, 3]]
    got: [[:b, 2, 3], [:c, nil, 4]]

    ./spec/exercises_spec.rb:190:in `block (2 levels) in <top (required)>’

  2. Hash#my_merge returns a hash with the correct key-value pairs
    Failure/Error: expect(test_hash_1.my_merge(test_hash_2) { |key, oldval, newval| newval - oldval }).to eq({a: -5, b: 8, c: 3})

    TypeError:
    nil can’t be coerced into Fixnum

I just ran your code and it passes all the specs. Here’s the code I ran (with improved formatting):

class Hash
  def my_merge(hash, &prc)
    prc ||= Proc.new { |k, oldval, newval| newval }
    new_hash = {}
    self.each do |key, value|
      new_hash[key] = hash[key] ? prc.call(key, value, hash[key]) : value
    end
    hash.each do |key, value|
      new_hash[key] = value if new_hash[key].nil?
    end
    new_hash
  end
end

Can you try running the specs again?

Hi! Thank you for the quick reply.
new_hash[key] = hash[key] ? prc.call(key, value, hash[key]) : value

I don’t understand this line, what is ? for? I’ve never learned this method.
And could you tell me what was wrong with my code?
Thanks!

I think we’re talking past each other. I just ran the code that you provided. Where did you get the code from?

The ? is called a ternary operator. The line new_hash[key] = hash[key] ? prc.call(key, value, hash[key]) : value works as follows. If hash[key] is truthy (not nil), then new_hash[key] gets assigned prc.call(key, value, hash[key]). Otherwise it gets assigned value.

Oh sorry! I must have accidentally pasted the solution I found online.
Below is my code:class Hash

Hash#merge takes a proc that accepts three arguments: a key and the two

corresponding values in the hashes being merged. Hash#merge then sets that

key to the return value of the proc in a new hash. If no proc is given,

Hash#merge simply merges the two hashes.

Write a method with the functionality of Hash#merge. Your Hash#my_merge method

should optionally take a proc as an argument and return a new hash. If a proc

is not given, your method should provide default merging behavior. Do not use

Hash#merge in your method.

def my_merge(hash2,&prc)

new_hash = self.dup
hash2.each do |k2, v2|
  unless block_given?
  new_hash[k2] = v2
  else
    new_hash[k2] = prc.call(k2,new_hash[k2],v2)
  end
end
new_hash

end
end

Gotcha!

The issue with your code is that you’re calling the block even if new_hash[k2] is not defined, i.e. if it’s nil. Try to think of a way to execute the line new_hash[k2] = prc.call(k2,new_hash[k2],v2) only if new_hash[k2] is defined.

Thank you so much!
I just added a conditional statement under my else, and it worked:
if new_hash[k2]
new_hash[k2] = prc.call(k2,new_hash[k2],v2)
else
new_hash[k2] = v2

Nice work! Glad you were able to figure it out!

1 Like