Map vs. Table for index-specific operations on 2D arrays

Many index-specific operations can be implemented via MapIndexed with a level specificaton. Your Power example can be written as:

MapIndexed[#1^(#2[[1]]*#2[[2]]) &, test2D, {2}]

If you want better readability of indices you can define an auxiliary function:

myPower[x_, {n1_, n2_}] := x^(n1 n2);
MapIndexed[myPower, test2D, {2}]

Some index-specific operations can be implemented without indices at all. The last example in your question can be coded in a functional form as:

Map[Downsample[#, 2, 2] &, Map[Partition[#, 4] &, test2Dx], {2}]

This expression can be also rewritten in a more verbose way:

splitInBlocksOf4 = Partition[#, 4] &;
takeEvenElements = Downsample[#, 2, 2] &;
Map[takeEvenElements, Map[splitInBlocksOf4, test2Dx], {2}]

In many cases, the functional approach is shorter, faster and less error-prone than index-based solutions.


We don't need to avoid Table in my view. In cases that Table is more straightforward, just use Table. If speed is concerned, Compile it. Here is an example:

Can I generate a "piecewise" list from a list in a fast and elegant way?

Nevertheless, your 2 examples (especially 2nd one) don't belong to the cases that Table is more straightforward, at least for someone familiar enough with list manipulation of Mathematica, I'm afraid. Do remember list manipulation is more than "Map and its variants".

The following is my solution:

# /@ #@test2D &[#^Range@Length@# &]   

Partition[#, 2] &@#[[2 ;; ;; 2]] & /@ test2Dx

BTW if test2D is not ragged i.e. ArrayQ returns True for test2D, I'll:

{dim1, dim2} = Range@Dimensions@test2D    
((test2D^dim1)\[Transpose]^dim2)\[Transpose]
(* Alternatively: *)
test2D^Outer[Times, dim1, dim2]