Delete method also deletes the original variable

Suppose a code is like this:

array1 = [1,2,3,4,5]
array2 = array1
array2.delete(1)

And the result was:

array2 => [2,3,4,5]
array1 => [2,3,4,5]

How do I make sure the first array stays original after the modification
of second array?

···

--
Posted via http://www.ruby-forum.com/.

Hi Vincent,

Try array1.dup, eg:

array2 = array1.dup

Cheers,
Garth

···

On 17/04/13 13:21, Vincent Stowbunenko wrote:

Suppose a code is like this:

array1 = [1,2,3,4,5]
array2 = array1
array2.delete(1)

And the result was:

array2 => [2,3,4,5]
array1 => [2,3,4,5]

How do I make sure the first array stays original after the modification
of second array?

Vincent Stowbunenko wrote in post #1105954:

How do I make sure the first array stays original after the modification
of second array?

Variables in ruby hold references to objects. This can be evidenced by
viewing the object_ids:

irb:001> array1 = [1,2,3,4,5]
irb:002> array2 = array1
irb:003> array2.object_id
=> 70171269757120
irb:004> array1.object_id
=> 70171269757120

To de-duplicate the reference you need to create a second object, which
is a copy of the first. The simplest way is to use `dup`

irb:005> array2 = array1.dup
irb:006> array1.object_id
=> 70171269757120
irb:007> array2.object_id
=> 70171269775520
# ^^^^^

irb:008> array1.delete(1)
irb:009> array1
=> [2, 3, 4, 5]
irb:010> array2
=> [1, 2, 3, 4, 5]

The thing to remember is that Array#dup performs a shallow copy. For
example:

irb:011> array1 = [[1,2,3],[4,5]]
irb:012> array2 = array1.dup
irb:013> array1[0].delete(1)
irb:014> array1
=> [[2, 3], [4, 5]]
irb:015> array2
=> [[2, 3], [4, 5]]

The variables `array1` and `array2` point to different Array objects,
but each of _those_ independently maintains references to the _same_
inner-arrays. In other words, array1[0] and array2[0] both reference
the same object.

It's not only limited to arrays, either:

irb:016> array1 = ['a']
irb:017> array2 = array1.dup
irb:018> array1[0] << 'b'
irb:019> array1
=> ["ab"]
irb:020> array2
=> ["ab"]

There is no general-form solution to creating a deep-copy of a
datastructure in ruby.

···

--
Posted via http://www.ruby-forum.com/\.

Thanks much for help! :slight_smile:

···

--
Posted via http://www.ruby-forum.com/.

Adding to what Garthy said: you need to be aware that there is only one
Array, not two as your speaking of a "first array" and "second array"
indicates. The effect is called "aliasing": two variables reference the
same instance. Btw, it happens all the time, for example when invoking
methods.

Another way of preventing changes to an Array is freezing it. That does
not automatically freeze the contained objects though!

Yet another way is to do the filtering in one step

irb(main):001:0> array1 = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):002:0> array2 = array1.reject {|x| x == 1}
=> [2, 3, 4, 5]
irb(main):003:0> array2 = array1[1..-1]
=> [2, 3, 4, 5]
irb(main):004:0> array2 = array1.slice(1..-1)
=> [2, 3, 4, 5]
irb(main):005:0> array1
=> [1, 2, 3, 4, 5]

Kind regards

robert

···

On Wed, Apr 17, 2013 at 5:51 AM, Vincent Stowbunenko <lists@ruby-forum.com>wrote:

Suppose a code is like this:

array1 = [1,2,3,4,5]
array2 = array1
array2.delete(1)

And the result was:

array2 => [2,3,4,5]
array1 => [2,3,4,5]

How do I make sure the first array stays original after the modification
of second array?

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

A (suboptimal) solution for deep copies in Ruby is to use Marshal.

It sure would be nice if Ruby had some sort of analogue for structured
cloning.

···

On Tue, Apr 16, 2013 at 9:10 PM, Matthew Kerwin <lists@ruby-forum.com>wrote:

There is no general-form solution to creating a deep-copy of a
datastructure in ruby.

--
Tony Arcieri

What exactly do you mean by "structured cloning"? Do you have ideas how
that should work?

Sketch:

# untested

class CloneContext
  def initialize
    @store = {}
  end

  def deep_clone(*objs)
    objs.map do |o|
      copy_one(o) rescue o
    end
  end

private
  def copy_one(obj)
    @store.fetch obj.object_id do |oid|
      (@store[oid] = obj.class.allocate).tap do |copy|
        # add specific handling for Array, String etc. or delegate to
#clone method of obj
        obj.instance_variables.each do |var|

copy.instance_variable_set(deep_clone(obj.instance_variable_get(var)))
        end
      end
    end
  end
end

Kind regards

robert

···

On Wed, Apr 17, 2013 at 7:34 AM, Tony Arcieri <tony.arcieri@gmail.com>wrote:

On Tue, Apr 16, 2013 at 9:10 PM, Matthew Kerwin <lists@ruby-forum.com>wrote:

There is no general-form solution to creating a deep-copy of a
datastructure in ruby.

A (suboptimal) solution for deep copies in Ruby is to use Marshal.

It sure would be nice if Ruby had some sort of analogue for structured
cloning.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

You can think of it as being somewhat akin to the marshal/unmarshal
approach, minus the intermediate string representation. For more
information I'd suggest reading how ECMAScript does it:

···

On Wed, Apr 17, 2013 at 3:00 AM, Robert Klemme <shortcutter@googlemail.com>wrote:

What exactly do you mean by "structured cloning"? Do you have ideas how
that should work?

--
Tony Arcieri