Reputation: 11
Why can't I combine newer
to older
?
def update_inventory(older, newer)
newer.each {|x, y| older[x] += y}
end
update_inventory({rubies: 10, emeralds: 14, diamonds: 2}, {emeralds: 27, moonstones: 5})
undefined method +' for
nil:NilClass
(repl):2:in block inupdate_inventory
(repl):2:ineach
(repl):2:inupdate_inventory
(repl):5:in<main>
Upvotes: 0
Views: 56
Reputation: 114158
It doesn't work as expected because older
does not contain all keys from newer
.
newer
consists of two key-value pairs: {emeralds: 27, moonstones: 5}
so newer.each
will invoke the block { |x, y| ... }
twice:
on the 1st iteration, x
is :emeralds
and y
is 27
which works just fine because older
has a value for :emeralds
:
older[:emeralds] #=> 14
older[:emeralds] += 27 #=> 41
on the 2nd iteration, x
is :moonstones
and y
is 5
, so you get:
older[:moonstones] #=> nil
older[:moonstones] += 5 #=> NoMethodError: undefined method `+' for nil:NilClass
The error is caused because Ruby tries to calculate nil + 5
and nil
doesn't have a +
method (hence "undefined method `+' for nil:NilClass").
To fix this, you could add a condition that checks whether the key exists. But there's a simpler way: Hash#update
does exactly what you need:
def update_inventory(older, newer)
older.update(newer) { |_, v1, v2| v1 + v2 }
end
It will copy the key-value pairs from newer
into older
. If a key exists in both hashes, the block will be called to determine the new value.
older = {rubies: 10, emeralds: 14, diamonds: 2}
newer = {emeralds: 27, moonstones: 5})
older.update(newer) { |_, v1, v2| v1 + v2 }
#=> {:rubies=>10, :emeralds=>41, :diamonds=>2, :moonstones=>5}
Upvotes: 5