How can I fill an array with empty 2D arrays?

Hello,
I am going into a loop which will produce N 2D arrays. I want to store them in an array, so I want to define it beforehand. I know the syntax for filling with empty 1D arrays but I can’t figure our the 2D version. Can you help me out?
Thanks

1D version that works
mat3Dtt = fill(Float64[],1, N);

2D version I can’t get to work

mat3Dtt = fill(Array{Float64,2},1, N);
julia> mat3Dtt[1]=rand(3,3)
ERROR: MethodError: Cannot `convert` an object of type Array{Float64,2} to an object of type DataType

You can do this, but be warned that fill repeats the same element, it doesn’t make copies.

julia> x = fill(Matrix{Float64}(undef,0,0), 3);

julia> x[1] = reshape(1:6,2,3);

julia> x  # ok!
3-element Vector{Matrix{Float64}}:
 [1.0 3.0 5.0; 2.0 4.0 6.0]
 0×0 Matrix{Float64}
 0×0 Matrix{Float64}

julia> y = fill(Matrix{Float64}(undef,2,3), 3);

julia> y[1] === y[2]
true

julia> y[1] .= reshape(1:6,2,3);

julia> y
3-element Vector{Matrix{Float64}}:
 [1.0 3.0 5.0; 2.0 4.0 6.0]
 [1.0 3.0 5.0; 2.0 4.0 6.0]
 [1.0 3.0 5.0; 2.0 4.0 6.0]

But you may be better off just letting a comprehension, or map, create the output for you. Or doing z = Matrix{Float64}[]; push!(z, reshape(1:6,2,3)).

3 Likes

i will go with that, thank you very much!

If you’re replacing the entire array that’s fine, but if you intend to predefine and then fill them, it’s still a problem:

x = fill(Matrix{Float64}(undef,2,2), 3);

julia> x
3-element Vector{Matrix{Float64}}:
 [2.75859452845e-313 3.3951932658e-313; 2.33419537065e-313 6.94677762088306e-310]
 [2.75859452845e-313 3.3951932658e-313; 2.33419537065e-313 6.94677762088306e-310]
 [2.75859452845e-313 3.3951932658e-313; 2.33419537065e-313 6.94677762088306e-310]

julia> x[1][1,1] = 5
5

julia> x
3-element Vector{Matrix{Float64}}:
 [5.0 3.3951932658e-313; 2.33419537065e-313 6.94677762088306e-310]
 [5.0 3.3951932658e-313; 2.33419537065e-313 6.94677762088306e-310]
 [5.0 3.3951932658e-313; 2.33419537065e-313 6.94677762088306e-310]

Make sure you understand @mcabbott’s warning:

That means you will get an array consisting of the same matrix 3 times. Modifying any one of those will modify all of them because they are all the same value. This is almost certainly not what you want in any application.

1 Like

Yeah, although if you’re doing that then pre-allocating the individual arrays is pointless, since they’ll be replaced regardless.

3 Likes

Yes, I am replacing the entire array, using it a bit like this:

julia> a=fill(Array{Float32,2}(undef,0,0),1,3);

julia> a[1]=rand(2,2); a[2]=rand(3,3);

julia> a[:]
3-element Array{Array{Float32,2},1}:
 [0.92491776 0.93883944; 0.9667731 0.9894779]
 [0.13091879 0.37846377 0.07404064; 0.71520746 0.9362733 0.41508183; 0.8309387 0.73587126 0.0631132]      
 Array{Float32}(undef,0,0)

I understand that I could just push the new one as it is generated, however I think pre-allocating makes the code more readable as you know where each array is going to go beforehand, instead of counting how many pushes there are.

1 Like

I see. Then perhaps what you actually need is:

a = Array{Array{Float32, 2}, 1}(undef, 3)

which is a Vector (a 1-D Array) whose elements are themselves matrices, with space allocated to hold 3 elements.

You can write that more simply as: Vector{Matrix{Float32}}(undef, 3) if you prefer.

4 Likes