How to stack two "cell arrays" together

I have two cell arrays, one of them
A is a 27x1 cell, size(A{i}) is 360x180.
B is a 35x1 cell, and size(B{i}) is the same as the above, i.e., 360x180.

How do I stack them together to create a C that has a size of 360x180x62?

Thanks.

Do you mean that you have A, B that are vectors (i e. 1-dim arrays) of matrices (i e. 2 dims arrays) and you want to stack them in a 3 dims Array?

Iā€™m not familiar with all these terms, but basically, A has 27 matrices. In Matlab I can call them like this:
A{1}
A{2}
ā€¦
A{27}.

What I want to get is a C that stacks up all these 27 matrices as well as the 35 matrices from B, thus producing a matrix with the size of 360x180x62.

Thanks.

If all you want is to concatenate A and B (both vectors where each entry is a matrix) to a C vector containing all the matrices you can use C = vcat(A,B), but this will NOT produce a 3 dimensional array, but a nested vector of matrices.

1 Like

maybe this is what you are looking for

A=rand(360,180,27);
B=rand(360,180,35);

c=[A;;;B]
#or

c=hvncat(3,A,B)


1 Like

Is this a Matlab or Julia question?

In Julia, there is no such thing as a cell array, though Array{Any, N} is similar. But assuming you have two vectors of matrices, you can do

C = cat(A..., B...; dims=3)
4 Likes

This looks like a MATLAB question.

In MATLAB, see cat.

You might vwant something like cat(3, A{:}, B{:}).

For MATLAB questions in the future see
https://www.mathworks.com/matlabcentral/

This is not a MATLAB help forum.

2 Likes

To clarify, this is a Julia question 100%. My apologies for the confusion. I just used the Matlab ā€œcell arrayā€ concept to describe the array, as I do not know how it is called within Julia.

Thanks for the recommended solution. Unfortunately, it does not work for me. My Julia would freeze every single time I tried this.

Thanks for the suggestions. However, my A and B are vectors of matrices, instead of 3d arrays.

What is your A and B in Julia?

In Julia, I would do this.

julia> begin
           A = [zeros(UInt8, 360, 180) for i in 1:27]
           B = [zeros(UInt8, 360, 180) for i in 1:35]
       end;

julia> C = [A...;;; B... ];

julia> size(C)
(360, 180, 62)

You can access inidivudal matrices as follows.

julia> A[1];

julia> A[27];

julia> B[27];

julia> C[60];

Basically we do not need the concept of cell array in Julia. Itā€™s just an array.

The literal equivalent of a cell array in Julia would be Array{N,Any} where N Array{N, Any} where N where each position of the array here could be anything.

julia> v = Vector{Any}(undef, 5);

julia> v[1] = 5
5

julia> v[2] = zeros(3,5)
3Ɨ5 Matrix{Float64}:
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0

julia> v[3] = true
true

julia> v[4] = 9.0
9.0

julia> v[5] = Ļ€
Ļ€ = 3.1415926535897...

julia> v
5-element Vector{Any}:
    5
     [0.0 0.0 ā€¦ 0.0 0.0; 0.0 0.0 ā€¦ 0.0 0.0; 0.0 0.0 ā€¦ 0.0 0.0]
 true
    9.0
    Ļ€ = 3.1415926535897...

In your case, however, you know all the elements are going to be of type Matrix{Float64} so we can be more specific.

julia> typeof(A)
Vector{Matrix{UInt8}} (alias for Array{Array{UInt8, 2}, 1})
1 Like

Iā€™m glad you found a solution, but Iā€™d like to point out that itā€™s a solution to a very different problem than the one described in the Original Post. It shows how to concatenate 3d arrays, but you were asking about vectors of matrices (ā€˜cell arrays of matricesā€™).

My proposed solution concerned itself vectors of matrices. If you feed it 3d arrays, itā€™s no surprise Julia froze, since it would try to compile a function with 4 million input arguments (360 * 180 * 62).

1 Like

You are exactly right. I got myself confused. As you mentioned, my A and B are not 3d arrays like the below.

A=rand(360,180,27);
B=rand(360,180,35);

Instead they are vectors of matrices like these:

begin
     A = [zeros(UInt8, 360, 180) for i in 1:27]
     B = [zeros(UInt8, 360, 180) for i in 1:35]
end;

As a result, your recommended solution as below works the best:

C = cat(A..., B...; dims=3)

Sorry for the confusion, but Iā€™m glad this post now has solutions for both 3d arrays and vectors of arrays.

Please donā€™t recommend to beginners that they splat arrays like this. Youā€™re just going to cause them problems and pain if they use an array thatā€™s too big since itā€™ll always incur a dynamic dispatch, and it creates large Tuples which can cause the compiler to freak out.

@Leon6 a more scalable way of doing this is with the stack function:

D = stack(vcat(A, B));

Hereā€™s a performance comparison:

julia> begin
            A = [zeros(UInt8, 360, 180) for i in 1:27]
            B = [zeros(UInt8, 360, 180) for i in 1:35]
       end;

julia> @btime C = cat($A..., $B...; dims=3);
  2.071 ms (573 allocations: 3.88 MiB)

julia> @btime D = stack(vcat($A, $B));
  104.551 Ī¼s (3 allocations: 3.83 MiB)

Easy 20x improvement.

2 Likes

Iā€™d like to point out that stack isnā€™t available in Julia yet, so think there should be a big disclaimer on that.

Also, I have frequently found that splatting performs annoyingly well, for some reason, even for large arrays. The performance characteristics of splatting remains a bit of a mystery to me.

1 Like

Since stack is unreleased as of Julia 1.8, you need to tell him how to do with pre-Julia 1.9.

stack is in Compat.jl.

2 Likes

Yes, sorry I misremembered and thought it was in 1.8. The ammended advice is to do (once)

using Pkg
Pkg.add("Compat")

and then once thatā€™s installed, you can do

using Compat: stack
D = stack(vcat(A, B));
1 Like
begin
    A = [rand(360, 180) for _ in 1:27]
    B = [rand(360, 180) for _ in 1:35]
end;

using BenchmarkTools

julia> @btime C=hvncat(3, A...,B...);
  543.363 ms (20024381 allocations: 397.52 MiB)

julia> @btime reshape(mapreduce(vec,vcat,A), (size(A[1])...,:));     
  41.736 ms (110 allocations: 186.39 MiB)
julia> @btime C = cat($A..., $B...; dims=3);
  6.810 ms (573 allocations: 30.70 MiB)

# cat seems 100X faster than hvncat(!?!?)

using Compat: stack

julia> @btime stack(vcat(A, B));
  6.774 ms (3 allocations: 30.65 MiB)

# using copyto! seems faster than stack

julia> @btime  begin
       C=similar(Array{Float64,3},(size(A[1])...,62));
       foreach(k->copyto!($C,1+360*180*(k-1), [A;B][k], 1, 360*180), 1:62)
       end
  4.009 ms (127 allocations: 30.69 MiB)

julia> @btime foreach(k->copyto!($C,1+360*180*(k-1), [A;B][k], 1, 360*180), 1:62)
  3.905 ms (123 allocations: 33.89 KiB)

julia> @btime begin
           C=similar(Array{Float64,3},(size(A[1])...,62));
           foreach(k->copyto!($C,1+360*180*(k-1), A[k], 1, 360*180), 1:27)
           foreach(k->copyto!($C,1+360*180*(k-1), B[k-27], 1, 360*180), 28:62)
       end
  4.167 ms (65 allocations: 30.65 MiB)

PS
I couldnā€™t use the copyto!() method which makes use of cartesianindices

2 Likes

Note that your second to last example doesnā€™t include the allocation of Cā€¦