I want to duplicate a hash using the same keys but different values. I coded up the following snippet, and encountered something I didn’t expect:
hsh = {:foo => 'foo', :bar => 'bar'}
hsh_copy = Hash[hsh.keys.zip([[]] * hsh.length)] # => {:foo=>[], :bar=>[]}
hsh_copy[:foo] << 1
hsh_copy[:bar] << 2
hsh_copy # => {:foo=>[1, 2], :bar=>[1, 2]}
It seems that instead of copying the nested array when using the * operator, it just continues to reference the first array.
I’d be very happy if someone could explain why this is happening. Additionally, a better way of duplicating the hash would be appreciated, but I’m more concerned with understanding why * doesn’t work as expected here.
If
Array#*copied the elements of the array, it would break when used on arrays with non-copyable elements (which includes, among others, numbers), which would not be desirable.As for how to do what you want to do: Replace
hsh.keys.zip([[]] * hsh.length)withhsh.map {|k,v| [k, []] }.