# How to convert Vector{Array{T,N}} to Array{T,N+1}

Is there any way (without using third party packages) to convert a vector of multi-dimensional array to multidimensional array, such as convert `[T_1,T_2,...,T_q]` (each `T_i` is a multi-dimensional array of type `Array{T,3}`, with size `r×s×t`) to multi-dimensional array `M` (of type `Array{T,4}`) with size `q×r×s×t` and `M[i,:,:,:,]` is identical to `T_i`

Thanks for the help!

Maybe this:

``````julia> vec_of_arr = fill(rand(3,4,5),6);

julia> arr = cat(vec_of_arr...,dims=4);

julia> size(arr)
(3, 4, 5, 6)

``````

You can use `permutedims(arr, (4,1,2,3))` to move the last axis to first position in indexing.

Check the documentation for `cat` and `permutedims` for more information.

1 Like

Thanks for this awesome solution, it works like a charm!

I am still quite confused about the design of multi-dimension array in Julia. Isn’t that quite intuitive to have vector of multi-dimensional arrays get raised to higher dimensional array with the first dimension indexing those original arrays? but cat seems do not support “create” a new dimension before existing dimensions.

1 Like

Kinda depends on how I interpret your question.

Vector of nD Arrays is basically a list of pointers to arrays, so iterating through it inherently requires following a pointer. This is different from an (n+1)D Array, which can be stored densely in a single contiguous piece of memory. This has fairly significant performance implications, thus I am happy that Julia makes interacting with them explicitly different.

If you do want the more convenient indexing, you can use tools like `RecursiveArrayTools.jl` which simplify the indexing for you.

Concerning why `cat` added a new index at the end instead of at the beginning, it is because I used `dims=4`. By the way, there is a literal version of `cat` that is equivalent: `[vec_of_arr...;;;;]` where the number of semicolons specifies the dimension along which you want to concatenate. Both `cat` and the literal inherit this style from how array literals work in julia: each semicolon adds a new dimension (at the back of the list of indices).

Lastly, the order of indices, I claim, is consistent with the fact that Julia has Fortran style, not C style matrices. I.e. the first index is the fastest growing one, not the last index. E.g. see this example:

``````julia> a = [1 3; 2 4] # or maybe a = [1; 2;; 3; 4] to make it more explicit
2×2 Matrix{Int64}:
1  3
2  4

julia> a, a, a, a # single-index lookup gives us the contiguous in-memory array
(1, 2, 3, 4)

julia> a[1,1], a[1,2] # modifying the last index causes discontinuous jumps
(1, 3)

julia> a[1,1], a[2,1] # modifying the first index gives neighbors
(1, 2)
``````

Thus, the first index should refer to contiguous neighbors-in-memory, while the last index should refer to big jumps in memory, which hopefully makes what you are observing make sense.

Also, the arrays inside a vector of arrays aren’t necessarily the same size, so they cannot even be automatically ‘promoted’ to `N+1` dimensions, in general.

1 Like

BTW, this is precisely what `stack(vec_of_arr; dims=1)`. For which you’ll need `using Compat` until Julia 1.9 emerges. This should be faster, especially if there are many arrays.

``````julia> vec_of_arr = fill(rand(3,4,5),6);

julia> arr = @btime permutedims(cat(\$vec_of_arr...; dims=4), (4,1,2,3));
min 4.607 μs, mean 5.812 μs (77 allocations, 9.00 KiB)

julia> arr ≈  @btime stack(\$vec_of_arr; dims=1)
min 231.739 ns, mean 602.204 ns (2 allocations, 2.98 KiB)
true
``````

Without `dims` it will put the vector’s index last, matching `cat(vec_of_arr...; dims=4)`. As mentioned that’s the natural order in memory, i.e. numbers which are at neighbouring addresses in each array are still neighbours in the final `arr`.

1 Like

I was curious what is the history of this newly added `stack` function. I suspect this would be interesting read for multiple people here:

1 Like