Reputation: 4336
I am doing a word problem. I am trying to set two arrays. One serves as a benchmark (doesn't change during iteration), the other changes during iteration. Here is an example:
seed = 1
a = [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1]]
bm = a[seed]
a[seed].each.with_index do |x, i|
if bm.include?(0)
a[seed][i] = "WRONG"
else
a[seed][i] = 0 unless i == 3
end
end
a # => [[1, 1, 1, 1], [0, "WRONG", "WRONG, "WRONG"], [1, 1]]
# Should be => [[1, 1, 1, 1], [0, 0, 0, 1], [1, 1]]
bm # => [0, "WRONG", "WRONG, "WRONG"]
# Should be => [1, 1, 1, 1]
Usually if you want to have a "before and after" in your code you can do:
a = 5
b = a
a = 6
a # => 6
b # => 5
In this case, it doesn't change b
when a
is changed. Why does this happen? I suspect it's because the second example is storing the number as b
whereas in the first example, it's storing the code only. What can I do to fix this? Is this bad practice?
Upvotes: 1
Views: 80
Reputation: 19879
You're right. When you assign the array to bm
you're really assigning a reference (or pointer, not sure what Ruby prefers to call it) to a[seed]
. You can see this by printing out the object_id
of both variables:
> a[seed].object_id
=> 70347648205960
> bm.object_id
=> 70347648205960
Note that they are pointing to the same internal object. The solution is to use dup
to duplicate the array and assign the new one to bm2
.
> bm2 = a[seed].dup
=> [1, 1, 1, 1]
> bm2.object_id
=> 70347649948520
Note the object_id has changed. And now if I make a change...
> a[seed][0] = 'WRONG'
=> "WRONG"
> a[seed]
=> ["WRONG", 1, 1, 1]
> bm
=> ["WRONG", 1, 1, 1]
> bm2
=> [1, 1, 1, 1]
You might want to Google to read about object_id
, dup
, and also clone
which is similar to dup, but has some differences.
Upvotes: 1