Reputation: 3
This is very bizzarre. Every time I run this code, in at least one iteration of the loop, one of the elements of my shuffled_couples
array is modified, messing up the final output. I have tested this with arrays that were not the product of shuffling couples_array
, and those arrays seem to be unaffected.
I inserted a number array in the place of shuffled_couple
inside the loop, and with each iteration, shuffled_couples
took on one more value from that numbers array, going from left to right:
couples_array = [
["Clyde", "Bonnie"],
["Paris", "Helen"],
["Romeo", "Juliet"]
]
shuffled_couples = couples_array.shuffle
couples_array.count.times do |idx|
puts "before loop #{idx}, shuffled_couples = : #{shuffled_couples}"
couples_array[idx][1] = shuffled_couples[idx][1]
puts "after loop #{idx}, shuffled_couples = : #{shuffled_couples}"
puts
end
puts
puts
puts "The final value of couples_array is #{couples_array}"
Before loop 0, shuffled_couples:
[["Paris", "Helen"], ["Clyde", "Bonnie"], ["Romeo", "Juliet"]]
After loop 0, shuffled_couples:
[["Paris", "Helen"], ["Clyde", "Helen"], ["Romeo", "Juliet"]]
Before loop 1, shuffled_couples:
[["Paris", "Helen"], ["Clyde", "Helen"], ["Romeo", "Juliet"]]
After loop 1, shuffled_couples:
[["Paris", "Helen"], ["Clyde", "Helen"], ["Romeo", "Juliet"]]
Before loop 2, shuffled_couples:
[["Paris", "Helen"], ["Clyde", "Helen"], ["Romeo", "Juliet"]]
After loop 2, shuffled_couples:
[["Paris", "Helen"], ["Clyde", "Helen"], ["Romeo", "Juliet"]]
The final value of couples_array
is:
[["Clyde", "Helen"], ["Paris", "Helen"], ["Romeo", "Juliet"]]
What is going on here? How can I fix it? I'm running Ruby 1.9.3.
Upvotes: 0
Views: 57
Reputation: 106832
You must first deep clone your array. That means you have to clone all elememts in the array (not only the array itself):
shuffled_couples = couples_array.map { |element| element.clone }
shuffled_couples = shuffled_couples.sample
Upvotes: 0
Reputation: 19855
It's behaving exactly as you told it to. You have to remember that with an array of arrays, the outer array actually contains references to the inner array. Let's look at the implications.
irb(main):001:0> couples_array = [
irb(main):002:1* ["Clyde", "Bonnie"],
irb(main):003:1* ["Paris", "Helen"],
irb(main):004:1* ["Romeo", "Juliet"]
irb(main):005:1> ]
=> [["Clyde", "Bonnie"], ["Paris", "Helen"], ["Romeo", "Juliet"]]
irb(main):006:0>
irb(main):007:0* shuffled_couples = couples_array.shuffle
=> [["Romeo", "Juliet"], ["Clyde", "Bonnie"], ["Paris", "Helen"]]
At this point, couples_array[0]
and shuffled_couples[1]
both point to the same array, ["Clyde", "Bonnie"]
. If I alter the second element by coming at it from either reference, the change will be visible when accessed/viewed from the other reference. It's exactly the same array, it's just being accessed by two different routes.
irb(main):008:0> couples_array[0][1] = 42 # replace "Bonnie" with 42
=> 42
irb(main):009:0> couples_array
=> [["Clyde", 42], ["Paris", "Helen"], ["Romeo", "Juliet"]]
irb(main):010:0> shuffled_couples
=> [["Romeo", "Juliet"], ["Clyde", 42], ["Paris", "Helen"]]
In this example, couples_array[0]
and shuffled_couples[1]
are exactly the same array, it's just being accessed by two different routes. If you reshuffled, depending on the luck of the draw you would often get different specific matches, but the underlying concept of what's going on would remain the same.
Upvotes: 1
Reputation: 2891
It looks like you need to make a deep copy of your array. You are pointing both of your arrays at the same instance and so are editing both of them in the loop. If you change your shuffle line to this:
shuffled_couples = couples_array.shuffle.clone
I think you'll get the results you expect. More on duplicating vs cloning in ruby here: https://coderwall.com/p/1zflyg/ruby-the-differences-between-dup-clone
Upvotes: 0