Using push!

I am using push! to store the value of an array in every iteration t. But, it does not work like I expect it to:

function trial(n)
  m=Any[]
  y=rand(10)
  for t in 1:n
    push!(m,y)
    for x in 10
      y[x]=rand()
    end
  end
  return m
end

On executing the above function for n=2, I get:

2-element Array{Any,1}:
 [0.3413498610074548, 0.9008040663934613, 0.10721629384140297, 0.5546157202036206, 0.794439983649
3246, 0.729274144801793, 0.1932248146434996, 0.2950370824859381, 0.9389225778706747, 0.0149528983
28812081]
 [0.3413498610074548, 0.9008040663934613, 0.10721629384140297, 0.5546157202036206, 0.794439983649
3246, 0.729274144801793, 0.1932248146434996, 0.2950370824859381, 0.9389225778706747, 0.0149528983
28812081]

As can be seen, the last known value of y is stored in all of m instead of the different values of y in each iteration. Is there something wrong in my understanding?

1 Like

When you push!(m,y) you are actually storing into m a reference to the array y, instead of copying the contents. That’s why if you modify an element in y, you will see the change in all of the elements of m: because you are actually looking inside the same y.

Take a look at:

julia> m = Any[]
0-element Array{Any,1}

julia> y = rand(3)
3-element Array{Float64,1}:
 0.3799842355542209
 0.789767043536056
 0.8862550043340174

julia> push!(m,y)
1-element Array{Any,1}:
 [0.3799842355542209, 0.789767043536056, 0.8862550043340174]

julia> push!(m,y)
2-element Array{Any,1}:
 [0.3799842355542209, 0.789767043536056, 0.8862550043340174]
 [0.3799842355542209, 0.789767043536056, 0.8862550043340174]

julia> y[2] = 1000;

julia> m
2-element Array{Any,1}:
 [0.3799842355542209, 1000.0, 0.8862550043340174]
 [0.3799842355542209, 1000.0, 0.8862550043340174]

You could certainly modify your function to make a copy of the current y and put it into m.

function trial_copy(n)
  m=Any[]
  y=rand(10)
  for t in 1:n
    push!(m,copy(y))
    for x in 10
      y[x]=rand()
    end
  end
  return m
end
2 Likes

I don’t understand, the effect of rand(10) and [rand() for _ in 1:10] are the same, why would you do this?

This is just an example I posted to understand how push! works. I am trying to use it in another code of mine

Thank you. I was thinking if there was a less expensive way of doing it since using copy results in more allocations and hence more time.

ah, so this is not about how push! works, this is just shallow copy (which is the norm, one could say).

julia> a = [1,2,3]
3-element Array{Int64,1}:
 1
 2
 3

julia> b = a

julia> a[1]=3
3

julia> b
3-element Array{Int64,1}:
 3
 2
 3
1 Like

In languages where assignment creates an independent array, you can avoid the copy when you assign but the copy is still made later if you modify either of the two arrays. This is “copy on write” behavior, which is how both R and Matlab do this. So your example would allocate in any language.

1 Like

Also, can I store arrays column-wise instead of row-wise which can be seen is the default of push!

They are not being stored row-wise, it’s just that when you have a vector of vectors, those inner vectors are printed in rows to fit more compactly on your screen.

julia> x = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

julia> y = [x, x]
2-element Array{Array{Int64,1},1}:
 [1, 2, 3]
 [1, 2, 3]

julia> y[1]
3-element Array{Int64,1}:
 1
 2
 3