# Using push! to add a new row of data

What is the proper way of using push to add rows to an existing matrix? I keep getting errors for the below code:

``````LL = fill(NaN, (0,2));
for j ∈ 1:n #180
for i ∈ 1:m #360
push!(LL, [X[i,j], Y[i,j]]);
end
end
``````

Many thanks!

You can only push to vectors, but not to multi-dimensional arrays. (See for example here Resize!(matrix) - #2 by StefanKarpinski why it is this way.)

• If you really need to add rows dynamically, you could consider using a `Vector` of `Vectors`
``````LL = Vector{Float64}[]
push!(LL, [1.0, 2.0])
``````
• If you only need to add a few rows/columns, you could use `vcat` or `hcat`. For example
``````LL = [X[:] Y[:]]   # or hcat(X[:],Y[:])  or  hcat(vec(X),vec(Y))
``````
• If you know in advance how many rows you need, that is of course ideal and it can sometimes give great performance benefits.
``````LL = fill(NaN, n*m, 2)  # or LL = Array{Float64}(undef, n*m, 2)
k = 1
for j ∈ 1:n #180
for i ∈ 1:m #360
LL[k, :] .= (X[i,j], Y[i,j])
k += 1
end
end
``````
2 Likes

Unfortunately, I got the errors as below:

``````LoadError: BoundsError: attempt to access 64800-element Vector{Vector{Float64}} at index [1:64800, 2]
Stacktrace:
 throw_boundserror(A::Vector{Vector{Float64}}, I::Tuple{Base.Slice{Base.OneTo{Int64}}, Int64})
@ Base ./abstractarray.jl:691
 checkbounds
@ ./abstractarray.jl:656 [inlined]
 _getindex
@ ./multidimensional.jl:838 [inlined]
 getindex(::Vector{Vector{Float64}}, ::Function, ::Int64)
@ Base ./abstractarray.jl:1218
 top-level scope
@ ~/Desktop/Julia_coding/A04_global_projection/XY.jl:41
``````

Which method did you try, and can you show your code?

If it is ok to push columns instead, you can use GitHub - JuliaArrays/ElasticArrays.jl: Resizeable multi-dimensional arrays for Julia.

When you use

``````LL = Vector{Float64}[]
push!(LL, [1.0, 2.0])
``````

you have to access the rows via `LL` (first row) or `LL ` first row, second element.

1 Like

Keep in mind that Julia arrays are ‘column-major’, so adding rows is highly disadvantageous. Can you change your data layout so that you are adding columns instead?

1 Like
``````LL = Vector{Float64}[]
push!(LL, [1.0, 2.0])
``````

That will work. All I need to do is to transpose the matrix after it is generated.

Is there an easier way to do so without relying on an external program package like “Elastic Arrays”? I mean in Matlab, it is as easy as `A = [A; B];`

It’s equally easy in Julia.

``````m = 360
n = 180
X = rand(m, n)
Y = rand(m, n)
LL = fill(NaN, (0,2));
for j ∈ 1:n #180
for i ∈ 1:m #360
LL = [LL; X[i, j] Y[i, j]]
end
end
``````

The performance of doing it this way is horrible but that’s the case for Matlab as well, or at least it was when I last used Matlab.

1 Like

Does anyone know why the code below does not work? Thanks

``````m = 360
n = 180
X = rand(m, n)
Y = rand(m, n)

LL = fill(NaN, (0,2));
for j ∈ 1:n #180
for i ∈ 1:m #360
var = [X[i,j] Y[i,j]];
global LL = reduce((x, y) -> cat(x, y; dims = 2), [LL, var]);
end
end
``````

Mostly because you try to concatenate along the wrong dimension. But there’s nothing you can gain by using `reduce` on two elements.

``````reduce((x, y) -> cat(x, y; dims = 2), [LL, var])
``````

is just a more complicated way, with some amount of overhead, to write

``````cat(LL, var; dims = 2)
``````
1 Like

Or just using concatenation syntax directly:

``````[LL var]  # cat along dim 2
[LL; var]  # cat along dim 1
``````
2 Likes

BTW, using `global` is discouraged (in all programming languages, not just Julia). Instead, you can put your code inside a function.

Here’s one way:

``````function mycat(X, Y)
LL = similar(X, 0, 2)
for i in eachindex(X, Y)
LL = [LL; [X[i] Y[i]]]
end
return LL
end
``````

But here’s a much better way:

``````function mycat2(X, Y)
LL = similar(X, length(X), 2)
for i in eachindex(X, Y)
LL[i, 1] = X[i]
LL[i, 2] = Y[i]
end
return LL
end
``````

The last one is 200.000 times faster, and runs in 80us instead of 16 seconds.

2 Likes