5
$\begingroup$

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.

$\endgroup$
6
$\begingroup$

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}}]
| improve this answer | |
$\endgroup$
  • $\begingroup$ 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}. $\endgroup$ – etotheix May 12 at 21:24
  • 1
    $\begingroup$ 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. $\endgroup$ – a20 May 12 at 21:55
  • $\begingroup$ 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. $\endgroup$ – etotheix May 12 at 22:35
  • 3
    $\begingroup$ 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}]]. $\endgroup$ – J. M.'s discontentment May 13 at 0:32
5
$\begingroup$
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.

| improve this answer | |
$\endgroup$
  • 1
    $\begingroup$ 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) $\endgroup$ – MarcoB May 12 at 21:10
  • 1
    $\begingroup$ Indeed, that also works. Just to point out to OP, /@ is equivalent to the Map[] function. That is, f/@list == Map[f[#] &, list]. $\endgroup$ – a20 May 12 at 21:14
1
$\begingroup$

For fun only:

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

list2 == rubeGoldberg @ list1
  True

and

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

rubeGoldberg2 @ list1 == list2
 True
| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.