# Convert matrix of 3D arrays to 3D array

**URL:** https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888
**Category:** General Usage
**Tags:** indexing, arrays, convert, tensors
**Created:** [July 21, 2023, 1:51pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888 "2023-07-21T13:51:42Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![mastrof](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mastrof/32/17443_2.png) [@mastrof](https://discourse.julialang.org/u/mastrof)
#### Post date: [July 21, 2023, 1:51pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/1 "2023-07-21T13:51:42Z")

</div>

I have `N^2` 3D arrays, all with size `(nx, ny, nz)`. These arrays are arranged in a square matrix (N x N). I would like to expand the inner arrays concatenating them along the first two dimensions but not along the third, so the end result should be a matrix with size `(N*nx, N*ny, nz)`.

For clarity, you can imagine the following scenario: I collected videos using N^2 cameras arranged in a grid, and now I want to stitch them into a single video.

So for a simple example you can consider I have these 4 arrays

```julia
a = rand(1, 2, 3)
b = rand(1, 2, 3)
c = rand(1, 2, 3)
d = rand(1, 2, 3)

```

and they are arranged as

```julia
M = [[a] [b]; [c] [d]]

```

what I want to do is transform `M` into a 3d array `V` whose dimensions are `(2, 4, 3)`. It should then satisfy  
`V[1:1, 1:2, :] == M[1,1]`, `V[1:1, 3:4, :] == M[1,2]`, `V[2:2, 1:2, :] == M[2,1]`, `V[2:2, 3:4, :] == M[2,2]`.

It didn’t feel too complicated initially but after trying various combinations of `hcat`, `vcat`, `cat`… I still did not find a simple solution.

Thanks

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [July 21, 2023, 2:10pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/2 "2023-07-21T14:10:58Z")

</div>

> [@mastrof](#):
>
> It didn’t feel too complicated initially but after trying various combinations of `hcat`, `vcat`, `cat`… I still did not find a simple solution

Did you try [`stack`](https://docs.julialang.org/en/v1/base/arrays/#Base.stack)?

---

<div class="post-metadata">

### Author: ![mastrof](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mastrof/32/17443_2.png) [@mastrof](https://discourse.julialang.org/u/mastrof)
#### Post date: [July 21, 2023, 3:14pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/3 "2023-07-21T15:14:04Z")

</div>

I didn’t manage to find a `stack` solution, but opening your link led me to `hvcat` (that I originally missed) which seems to do exactly what I want as `hvcat(size(M,2), permutedims(M)...)` (which also works if `M` is not square).

If anyone has other approaches to propose I’d be happy to learn them still.

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [July 21, 2023, 8:27pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/4 "2023-07-21T20:27:59Z")

</div>

```julia
vcat((hcat(r...) for r in eachrow(M))...)

```

```julia
reshape( permutedims(stack(M),(1,4,2,5, 3)), 2,4,3)

```

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [July 21, 2023, 8:36pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/5 "2023-07-21T20:36:51Z")

</div>

```julia
reshape(stack(M,dims=(2)), 2,4,3)

```

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [July 21, 2023, 10:39pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/6 "2023-07-21T22:39:58Z")

</div>

> [@rocco\_sprmnt21](#):
>
> `reshape(stack(M,dims=(2)), 2,4,3)`

This one looks nice and compact but it does not seem to deliver the result requested by OP?

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [July 22, 2023, 7:25am UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/7 "2023-07-22T07:25:28Z")

</div>

Yes. I think so too.  
Maybe it can be useful to a future OP 😁.  
I propose a different one.

```julia
splat(hcat)(splat(vcat).(eachcol(M)))

```

I confess that these transformations are not very intuitive, in most cases

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [July 22, 2023, 10:06am UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/8 "2023-07-22T10:06:35Z")

</div>

[TensorCast](https://github.com/mcabbott/TensorCast.jl) has a notation for that type of reshaping:

```julia
using TensorCast
@cast V[n ⊗ nx, m ⊗ ny, nz] := M[n, m][nx, ny, nz]

```

and using `@macroexpand` you can easily check what functions it uses under the hood. Further, `"⊗"` can be typed by `\otimes<tab>`.

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [July 22, 2023, 12:50pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/9 "2023-07-22T12:50:44Z")

</div>

the solution with tensorcast seems to lead to the same result as  
`reshape(stack(M,dims=(2)), 2,4,3)`  
which seems to be a more “simple/direct” casting than the one requested by the OP

using @macroespand you can see that the scheme adopted by tensor cast seems similar to the one adopted by me in a previous solution.

```julia
@macroexpand @cast V[n ⊗ nx, m ⊗ ny, nz] := M[n, m][nx, ny, nz]

# local var"##n...#298" = TensorCast.transmute(TensorCast.lazystack(M), Base.Val((4, 1, 5, 2, 3)))
# V = Base.reshape(var"##n....#298", (TensorCast.star(ax_n, ax_nx), TensorCast.star(ax_m, ax_ny), ax_nz))

reshape( permutedims(stack(M),(4,1,5,2, 3)), 2,4,3)

```

the difference lies in the different permutation used

```julia
reshape( permutedims(stack(M),(1,4,2,5, 3)), 2,4,3)

```

---

<div class="post-metadata">

### Author: ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)
#### Post date: [July 22, 2023, 1:41pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/10 "2023-07-22T13:41:33Z")

</div>

For TensorCast I think the question wants the indices the other way around. The index from the inner array should be the fast-changing one, hence left-most in `nx⊗Nx` etc.

```julia
julia> using TensorCast

julia> @cast _[(i,I), (j,J), k] := M[I,J][i,j,k]
2×4×3 reshape(transmute(lazystack(::Matrix{Array{Float64, 3}}), (1, 4, 2, 5, 3)), 2, 4, 3) with eltype Float64:
[:, :, 1] =
 0.076708 0.830297 0.657548 0.394117
 0.954511 0.442791 0.0738904 0.103809
...

julia> @cast out[nx⊗Nx, ny⊗Ny, nz] |= M[Nx, Ny][nx, ny, nz] # writing ⊗ to look like question...
2×4×3 Array{Float64, 3}: # ... and |= is less lazy, collects an Array, with same numbers
[:, :, 1] =
 0.076708 0.830297 0.657548 0.394117
 0.954511 0.442791 0.0738904 0.103809
...

julia> out ≈ hvcat(size(M,2), permutedims(M)...)
true

```

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [July 22, 2023, 3:07pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/11 "2023-07-22T15:07:54Z")

</div>

Sorry, had missed that detail of the question. The good think is that `TensorCast` is very explicit and allows to easily change the indexing (thanks to @mcabbott for fixing it).

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [July 22, 2023, 9:28pm UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/12 "2023-07-22T21:28:40Z")

</div>

@mcabbott, if you allow me, your ideas are quite impressive.

---

<div class="post-metadata">

### Author: ![mastrof](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mastrof/32/17443_2.png) [@mastrof](https://discourse.julialang.org/u/mastrof)
#### Post date: [July 23, 2023, 9:05am UTC](https://discourse.julialang.org/t/convert-matrix-of-3d-arrays-to-3d-array/101888/13 "2023-07-23T09:05:04Z")

</div>

Thanks for all the suggestions! In particular the TensorCast solution looks fantastic, I didn’t know the package.  
I guess I should ask questions more often, there’s always something new to learn around here
