**Adding Dimensions**
So far, you've dealt with only one-dimensional arrays, which isn't really very challenging. So let's add more data. Creating a two-dimensional cube is just like creating a one-dimensional cube, only you need two dimensions of data:

| |

Figure 4. A Two-dimensional Cube: The figure shows a visualization of the data in a two-dimensional cube. |

```
Integer data[][] = { { 1010, 1020, 1030 },
{ 2010, 2020, 2030 },
{ 3010, 3020, 3030 } };
Cube cube = new Cube( data );
```

This two-dimensional cube looks like

Figure 4.

Map works on a two-dimensional array just like it did on a one-dimensional array. Applying 'doubler' to this gives you what you would expect, as shown in

Figure 5:

A fold works just fine on a two-dimensional array as well. Remember that a fold reduces the number of dimensions by one. Just as you used fold to turn a one-dimensional array (10, 20, 30) into a single number value (the sum 60), you can use a fold to turn a two-dimensional array into a one-dimensional array:

| |

Figure 5. A Doubled Two-dimensional Cube: Doubling works on a two-dimensional cube just as it does on a one-dimensional cube. |

```
Cube f = cube.fold( 'plus', 0 );
```

Folding the cube that way results in a single column of values, as shown in

Figure 6.

| |

Figure 6. A Folded Two-dimensional Cube: Folding works on multi-dimensional cubes as well. |

**Playing with Axes**
In higher dimensions, you may often it useful to move the axes around. For example, you might want to swap the axes of the two-dimensional array from the last section. That is, you might want to turn the array shown in

Figure 4 into the form shown in

Figure 7.

No problem. You simple permute the axes:

```
int permutation[] = { 1, 0 };
Cube pcube = cube.permuteAxes( permutation );
```

| |

Figure 7: Swapping Axes: The figure shows a two-dimensional cube after swapping axes. |

The array

{ 1, 0 } controls how to build the output array. In this case, the code will change the array so that axis #1 of the input becomes axis #0 of the output, and axis #0 of the input becomes axis #1 of the output. In other words, the code swaps them.

Map and fold are powerful operations. Their power lies in the fact that they don't actually describe the computation to be performed—they only describe the way to traverse the data. The computation itself is passed in as a Fun or Fun2.

This separation of traversal from computation is a staple of functional programming; it also touches on the "separation of concerns" idea from Aspect-oriented programming. Thus, the maps and folds shown here are only the beginning; it's up to you to create new functions to map and fold across your data structures.