1

Given a multidimensional array, such as the 3-dimensional 2 x 2 x 3 array

{
 {{a,b,c},{d,e,f}},
 {{g,h,i},{j,k,l}}
}

How can I extract an arbitrary 3-dimensional contiguous subarray, such as slice 1, rows 1-2 and columns 2-3, which is

{
 {{b,c},{e,f}}
}

This is not too hard, using Part, Take, Extract, etc.

But how can I do it for an array of arbitrary dimension d? Must I use recursion somehow ?

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Simon
  • 1,415
  • 8
  • 13

1 Answers1

3

It is very easy using Part, which allows specifications of arbitrary depth, and Span:

m = {{{a, b, c}, {d, e, f}}, {{g, h, i}, {j, k, l}}}

m[[1, 1 ;; 2, 2 ;; 3]]
{{b, c}, {e, f}}

If you want full bracket depth in the output make any single part specification a List:

m[[{1}, 1 ;; 2, 2 ;; 3]]
{{{b, c}, {e, f}}}

See: Head and everything except Head?


This is an attempt to address an example provided in the comments. As I understand it your example can be reduced to:

x = Fold[Partition, Range@12, {3, 2}]

MapThread[# ;; # + #2 - 1 &, {{1, 2, 2}, {2, 1, 2}}]

x[[##]] & @@ %
{{{1, 2, 3}, {4, 5, 6}}, {{7, 8, 9}, {10, 11, 12}}}

{1 ;; 2, 2 ;; 2, 2 ;; 3}

{{{5, 6}}, {{11, 12}}}

There is nothing about this that is restricted to three dimensions as far as I can see.
Here is the same code again with a larger tensor:

x = Fold[Partition, Range@72, {3, 4, 2}];

x[[##]] & @@ MapThread[# ;; # + #2 - 1 &, {{1, 2, 1, 2}, {2, 1, 2, 2}}]
{{{{14, 15}, {17, 18}}}, {{{38, 39}, {41, 42}}}}

Other ways to write the same operation:

a = {1, 2, 1, 2};
b = {2, 1, 2, 2};

Inner[# ;; # + #2 - 1 &, a, b, x[[##]] &]
{{{{14, 15}, {17, 18}}}, {{{38, 39}, {41, 42}}}}
Take[x, ##] & @@ ({a, a + b - 1}\[Transpose])
{{{{14, 15}, {17, 18}}}, {{{38, 39}, {41, 42}}}}
Take[Drop[x, ##] & @@ (a - 1), ##] & @@ b
{{{{14, 15}, {17, 18}}}, {{{38, 39}, {41, 42}}}}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Thank you very much @Mr.Wizard and blochwave. Here is an example of what I mean: arraydims = {2, 2, 3}; cases = Tuples[{0, 1}, arraydims]; badsubarraydims = {2, 1, 2};badsubarrayoffset={1, 2, 2};cases[[792]] – Simon Mar 19 '15 at 19:39
  • Now %[[badsubarrayoffset[[1]];;badsubarrayoffset[[1]]+badsubarraydims[[1]]-1, badsubarrayoffset[[2]];;badsubarrayoffset[[2]]+badsubarraydims[[2]]-1, badsubarrayoffset[[3]];;badsubarrayoffset[[3]]+badsubarraydims[[3]]-1] – Simon Mar 19 '15 at 19:43
  • will extract a contiguous 2x1x2 array from the 2x2x3 array, but how can I remove the inherent 3-dimensional-ness from the extraction command ? I would like to pass that command the parameter Length[arraydims], which in this case would be 3, so that the code works equally well in dimension 1,2,3,4,etc. – Simon Mar 19 '15 at 19:45
  • @Simon I am not sure I understand your problem but I shall attempt to provide something helpful anyway. I shall update this answer soon. – Mr.Wizard Mar 20 '15 at 10:16
  • Dear @Mr.Wizard, thank you very much indeed ! I think that is exactly what I want. I see that your code is dimension-free: You could substitute arbitrary lists of arbitrary length in place of the particular lists you have used, provided the dimensions agreed etc. Thank you so much again ! – Simon Mar 21 '15 at 18:03
  • @Simon If you find this answer fully satisfactory please consider Accepting it. See: (5234) – Mr.Wizard Mar 22 '15 at 05:49