dangerousdave dangerousdave - 3 months ago 8
Ruby Question

Duplicating a Ruby array of strings

arr = ["red","green","yellow"]

arr2 = arr.clone
arr2[0].replace("blue")

puts arr.inspect
puts arr2.inspect


produces:

["blue", "green", "yellow"]
["blue", "green", "yellow"]


Is there anyway to do a deep copy of an array of strings, other than using Marshal as i understand that is a hack.

I could do:

arr2 = []
arr.each do |e|
arr2 << e.clone
end


but it doesn't seem very elegant, or efficient.

Thanks

Answer

Your second solution can be shortened to arr2 = arr.map do |e| e.dup end (unless you actually need the behaviour of clone, it's recommended to use dup instead).

Other than that your two solutions are basically the standard solutions to perform a deep copy (though the second version is only one-level deep (i.e. if you use it on an array of arrays of strings, you can still mutate the strings)). There isn't really a nicer way.

Edit: Here's a recursive deep_dup method that works with arbitrarily nested arrays:

class Array
  def deep_dup
    map {|x| x.deep_dup}
  end
end

class Object
  def deep_dup
    dup
  end
end

class Numeric
  # We need this because number.dup throws an exception
  # We also need the same definition for Symbol, TrueClass and FalseClass
  def deep_dup
    self
  end
end

You might also want to define deep_dup for other containers (like Hash), otherwise you'll still get a shallow copy for those.