It is perhaps worth noting that if
a = [["cat", "pig"], "hat", "dog"] # => [["cat", "pig"], "hat", "dog"]
b = a.dup # => [["cat", "pig"], "hat", "dog"]
then
a[0].delete_at(0)
a # => [["pig"], "hat", "dog"]
b # => [["pig"], "hat", "dog"]
Here you'd need to do this:
a = [["cat", "pig"], "hat", "dog"]
b = a.dup
b[0] = a[0].dup
a[0].delete_at(0)
a # => [["pig"], "hat", "dog"]
b # => [["cat", "pig"], "hat", "dog"]
Now suppose a were much more complicated, say, an array of hashes whose values are arrays of hashes. Obviously, one must take care in making a copy of a that will be unaffected by the deletion of some deeply-nested element of a. What you would want is called a "deep copy", as opposed to the "shallow" copy made by Object#dup and Object#clone.
Fortunately, there is an easy way to make a deep-copy of any object, using Marshal#dump and Marshal#load:
b = Marshal.load(Marshal.dump(a))
a[0].delete_at(0)
a # => [["pig"], "hat", "dog"]
b # => [["cat", "pig"], "hat", "dog"]
As an aside, Marshal is also used to save an object to file for later retrieval:
File.open('myfile', 'w+') do |f|
Marshal.dump(a, f)
end
File.open('myfile') do |f|
c = Marshal.load(f)
end
c # => [["cat", "pig"], "hat", "dog"]
A word of caution: Marshal files are not not portable among all versions of Ruby.