# Partitioning a multidimensional list into blocks using element positions

How can I partition elements of an (n x m x t) list into blocks of (n x m) using positions in the (t) dimension as reference? In other words, I would like all [[All,All,1]] elements to be grouped together in one block, and so on for all elements in (t).

For example, if I have the following list where n=4, m=4 and t=5:

list1 = {{{1,2,3,4,5},{6,7,8,9,10}},{{11,12,13,14,15},{16,17,18,19,20}}}


How can I transform it to obtain the following result?

list2 = {{{{1,6},{11,16}}},{{{2,7},{12,17}}},{{{3,8},{13,18}}},{{{4,9},{14,19}}},{{{5,10},{15,20}}}}


More details on what I would like to do:

The reason I am asking is because I would like to perform a multidimensional Fourier transform on list1, starting with a 1D Fourier transform in the (t) dimension, followed by a 2D Fourier transform in the (n x m) dimension.

I would like to first perform the 1D Fourier transform on list1 in the following way:

fourierList1 = Map[Fourier, list1, {2}]


Such that:

fourierList1 = {{Fourier[{a,b,c,d,e}],Fourier[{f,g,h,i,j}}],{Fourier[{k,l,m,n,o}],Fourier[{p,q,r,s,t}]}}


Suppose that the result is:

fourierList1 = {{{1,2,3,4,5},{6,7,8,9,10}},{{11,12,13,14,15},{16,17,18,19,20}}}


Then I would like to transform fourierList1 by grouping elements in the way described above and obtain another list called fourierList2.

fourierList2 = {{{{1,6},{11,16}}},{{{2,7},{12,17}}},{{{3,8},{13,18}}},{{{4,9},{14,19}}},{{{5,10},{15,20}}}}


Then I would like to map a 2D Fourier transform on fourierList2:

fourierList3 = Map[Fourier, fourierList2 , {2}]


And finally, transform fourierList3 back into the original (n x m x t) list format.

You can use Transpose:

List /@ Transpose[list1, {2, 3, 1}] == list2


True

J.M. shared two similar solutions in his comment below:

Transpose[{list1}, {2, 3, 4, 1}]


and

Flatten[{list1}, {{4}, {1}, {2}, {3}}]

• Thank you! Would you mind also sharing how you would convert back to list1 using list2 as input? I am reading the documentation, but I am not sure I understand how the Transform works with the option {2, 3, 1}. May 12 '20 at 21:24
• Transpose[list2[[All,1]],{3,1,2}] converts list2 to list1. What it means is that the 3rd level of list2[[All,1]], becomes the first level, the 1st level becomes the second level, and finally the 2nd level becomes the third level. For example, Transpose[{{1,2,3},{4,5,6},{a,b}]. If {a,b}={1,2}, the matrix is unchanged, wheras for {2,1} you have the normal two-dimensional transpose, changing rows into columns. It is best if you play around a bit with it I think... Anyway, this is why I think my answer might be somewhat easier to understand, even though it is less efficient.
– a20
May 12 '20 at 21:55
• Hi a20, thank you for the explanation. If I may ask, how would you reverse this transformation? I am trying to split the 2x2 blocks back into 1x2 blocks using: Map[Partition[#, 2] &, list2, {3}] but the partitioning is creating an extra level. May 12 '20 at 22:35
• Also doable with a single Transpose[]: Transpose[{list1}, {2, 3, 4, 1}], or a Flatten[]: Flatten[{list1}, {{4}, {1}, {2}, {3}}]. The relationship between these two variants can be seen if you evaluate {4, 1, 2, 3}[[{2, 3, 4, 1}]]. May 13 '20 at 0:32
tmp = Map[#\[Transpose]&,list1]\[Transpose]
res = Map[{#}&,tmp]

out: {{{1, 6}, {11, 16}}, {{2, 7}, {12, 17}}, {{3, 8}, {13, 18}}, {{4,
9}, {14, 19}}, {{5, 10}, {15, 20}}}
out: {{{{1, 6}, {11, 16}}}, {{{2, 7}, {12, 17}}}, {{{3, 8}, {13,
18}}}, {{{4, 9}, {14, 19}}}, {{{5, 10}, {15, 20}}}}

TrueQ[res==list2]
out: True


EDIT:

The answer by C.E., as well as the suggestion in the comment to this answer, are about 2 times faster than my answer, on my computer. Although I think my answer is quite intuitive, it is clearly not the most efficient, which is important if you are considering large data sets.

• res may also be written as List /@ Transpose[Transpose /@ list1]. That's the exact same process you have, of course; I only find it more readable. (+1) May 12 '20 at 21:10
• Indeed, that also works. Just to point out to OP, /@ is equivalent to the Map[] function. That is, f/@list == Map[f[#] &, list].
– a20
May 12 '20 at 21:14

For fun only:

rubeGoldberg = # /* # /* Map[#] /* # /* Map[{##} &] & @ Transpose;

list2 == rubeGoldberg @ list1

  True


and

rubeGoldberg2 = Nest[List @* Map[Transpose], #, 3][[1, 1]] &;

rubeGoldberg2 @ list1 == list2

 True