1
$\begingroup$

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 ?

$\endgroup$
1
  • 1
    $\begingroup$ "This is not too hard, using Part, Take, Extract, etc." What have you tried? Can you share some code? $\endgroup$ – dr.blochwave Mar 19 '15 at 12:55
3
$\begingroup$

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}}}}
$\endgroup$
6
  • $\begingroup$ 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]] $\endgroup$ – Simon Mar 19 '15 at 19:39
  • $\begingroup$ Now %[[badsubarrayoffset[[1]];;badsubarrayoffset[[1]]+badsubarraydims[[1]]-1, badsubarrayoffset[[2]];;badsubarrayoffset[[2]]+badsubarraydims[[2]]-1, badsubarrayoffset[[3]];;badsubarrayoffset[[3]]+badsubarraydims[[3]]-1] $\endgroup$ – Simon Mar 19 '15 at 19:43
  • $\begingroup$ 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. $\endgroup$ – Simon Mar 19 '15 at 19:45
  • $\begingroup$ @Simon I am not sure I understand your problem but I shall attempt to provide something helpful anyway. I shall update this answer soon. $\endgroup$ – Mr.Wizard Mar 20 '15 at 10:16
  • $\begingroup$ 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 ! $\endgroup$ – Simon Mar 21 '15 at 18:03

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.