Weird result when updating an array element

Given the code below, only one element in @ver should be changed, however when I execute the code all the elements are changed. Can anyone explain why this is happening?

class SomeClass
    def initialize
        @ver = Array.new(2, {'pos' => Array.new(3), 'col' => Array.new(4)})
        @ver[0]['pos'][0] = 0
        puts @ver.inspect
    end
end
SomeClass.new

actual result:
[{"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}, {"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}]

expected result:
[{"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}, {"col"=>[nil, nil, nil, nil], "pos"=>[nil, nil, nil]}]

Nelson Owen wrote:

Given the code below, only one element in @ver should be changed, however when I execute the code all the elements are changed. Can anyone explain why this is happening?

class SomeClass
   def initialize
       @ver = Array.new(2, {'pos' => Array.new(3), 'col' => Array.new(4)})
       @ver[0]['pos'][0] = 0
       puts @ver.inspect
   end
end
SomeClass.new

actual result:
[{"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}, {"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}]

expected result:
[{"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}, {"col"=>[nil, nil, nil, nil], "pos"=>[nil, nil, nil]}]

from the Array docs:

...it is created with size copies of obj (that is, size references to the same obj).

So ver[0] and ver[1] are in fact pointing to the same object.

You can use:

@ver = Array.new(2) {{'pos' => Array.new(3), 'col' => Array.new(4)}}

wich looks odd, but works :slight_smile:

cheers

Simon

Given the code below, only one element in @ver should be changed,
however when I execute the code all the elements are changed. Can
anyone explain why this is happening?

class SomeClass
   def initialize
       @ver = Array.new(2, {'pos' => Array.new(3), 'col' =>
       Array.new(4)}) @ver[0]['pos'][0] = 0
       puts @ver.inspect
   end
end
SomeClass.new

actual result:
[{"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}, {"col"=>[nil,
nil, nil, nil], "pos"=>[0, nil, nil]}]

expected result:
[{"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}, {"col"=>[nil,
nil, nil, nil], "pos"=>[nil, nil, nil]}]

You are creating a two element array where the same hash is referenced for each array element:

obj = Object.new

=> #<Object:0x101928d0>

obj.object_id

=> 135042152

a=Array.new(3,obj)

=> [#<Object:0x101928d0>, #<Object:0x101928d0>, #<Object:0x101928d0>]

a.map {|o| o.object_id}

=> [135042152, 135042152, 135042152]

a.map {|o| o.object_id}.uniq

=> [135042152]

You want the block form of array init:

a = Array.new(3) { Object.new }

=> [#<Object:0x1017a528>, #<Object:0x1017a480>, #<Object:0x1017a3f0>]

a.map {|o| o.object_id}

=> [134992532, 134992448, 134992376]

a.map {|o| o.object_id}.uniq

=> [134992532, 134992448, 134992376]

In your case

@ver = Array.new(2){ {'pos' => Array.new(3), 'col' => Array.new(4)} }

Kind regards

    robert

···

Nelson Owen <nowen@i-55.com> wrote:

Simon Kröger wrote:

Nelson Owen wrote:

Given the code below, only one element in @ver should be changed, however when I execute the code all the elements are changed. Can anyone explain why this is happening?

class SomeClass
   def initialize
       @ver = Array.new(2, {'pos' => Array.new(3), 'col' => Array.new(4)})
       @ver[0]['pos'][0] = 0
       puts @ver.inspect
   end
end
SomeClass.new

actual result:
[{"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}, {"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}]

expected result:
[{"col"=>[nil, nil, nil, nil], "pos"=>[0, nil, nil]}, {"col"=>[nil, nil, nil, nil], "pos"=>[nil, nil, nil]}]

from the Array docs:

...it is created with size copies of obj (that is, size references to the same obj).

So ver[0] and ver[1] are in fact pointing to the same object.

You can use:

@ver = Array.new(2) {{'pos' => Array.new(3), 'col' => Array.new(4)}}

wich looks odd, but works :slight_smile:

cheers

Simon

.

Ah, I see now. Thanks!