# Re: [S09] "Whatever" indices and shaped arrays

```Jonathan Lang  wrote:
```
```Larry Wall wrote:
> : If you want the last index, say '*[-1]' instead of '* - 1'.
> : If you want the first index, say '*[0]' instead of '* + 0'.
>
> So the generic version of leaving off both ends would be *[1]..*[-2]
> (ignoring that we'd probably write *[0]^..^*[-1] for that instead).```
```
Correct - although that assumes that the indices are consecutive (as
opposed to, say, 1, 2, 4, 8, 16...); this version of * makes no such
assumption.
```
```
Another thought: '*[1..-2]' or '*[0^..^-1]' would do the trick here -
except for the fact that the Range 1..-2 doesn't normally make sense.
Suggestion: when dealing with Ranges in unshaped arrays, negative
endpoints are treated like negative indices (i.e., '\$_ += [EMAIL PROTECTED]').

In effect, using * as an array of indices gives us the ordinals
notation that has been requested on occasion: '*[0]' means 'first
element', '*[1]' means 'second element', '*[-1]' means 'last element',
'*[0..2]' means 'first three elements', and so on - and this works
regardless of what the actual indices are.

```
```Like I said, I tend to miss intricacies.  For instance, I never
considered what would be involved in applying a subscriptor to a
multidimensional Whatever (e.g., what can you do with '**[...]'?).
Part of that is that I'm not yet comfortable with multidimensional
slices (or arrays, for that matter); when reading about them, I keep
on getting the feeling that there's something going on here that the
big boys know about that I don't - implicit assumptions, et al.
```
```
I think I've got a better grip on it now.  Here's how I understand it to work:

A multidimensional array is defined by providing a list of lists, each
giving all of the valid indices along one axis (i.e., in one
dimension).  The overall shape of the array will be rectangular, or a
higher-dimensional analog of rectangular.  There may be gaps in the
indices (in which case the array is a sparse array as well as a
multidimensional array); but if there are, the gaps also conform to
the rectangular structure: it's as if you carved a solid rectangle
into two or more rectangular pieces and pulled them apart a bit.  That
is, @array[-1, +1; -1 +1] is effectively a 2x2 square array with valid
x-indices of -1 and +1 and valid y-indices of -1 and +1.

To access an element in a multidimensional array, use a
semicolon-delimited list of indices in the square braces:
'@cube[1;1;1]' will access the center element of a [^3;^3;^3] shaped
array, while '@array[*;*;1]' will access a 3x3 horizontal slice of it.

When putting together a list literal, things work a bit differently.
Create a one-dimensional literal by means of a comma-delimited list of
values; create a two-dimensional literal by means of a
semicolon-delimited list of comma-delimited lists of values:

1, 2, 3 # one-dimensional list literal with a length of 3
(1, 2, 3; 4, 5, 6) # two-dimensional list literal with a length of 2
and a width of 3.
(1; 2; 3) # two-dimensional list literal with a length of 3 and a width of 1.

I would guess that you would build higher-dimensional "literals" by
nesting parentheses-enclosed semicolon-delimited lists:

(( 0,  1;  2,  3;  4,  5;  6,  7;  8,  9);
(10, 11; 12, 13; 14, 15; 16, 17; 18, 19);
(20, 21; 22, 23; 24, 25; 26, 27; 28, 29))
# three-dimensional list literal with a length of 3, a width of 5, and
a height of 2.

The outermost set of semicolons delimits the first dimension, and the
commas delimit the last dimension.  That is, semicolon-delimited lists
nest, and comma-delimited lists flatten.

Furthermore, the "list literal" gets assigned to the array by means of
ordinal coordinates:

my @cube[-1..+1; -1..+1; -1..+1] =
((1, 2, 3; 4, 5, 6; 7, 8, 9);
(10, 11, 12; 13, 14, 15; 16, 17, 18);
(19, 20, 21; 22, 23, 24; 25, 26, 27));

would be equivalent to

my @cube[1..3; 1..3; 1..3];
@cube[**[0; **]] = (1, 2, 3; 4, 5, 6; 7, 8, 9);
@cube[**[0; **]] = (10, 11, 12; 13, 14, 15; 16, 17, 18);
@cube[**[0; **]] = (19, 20, 21; 22, 23, 24; 25, 26, 27);

or

my @cube[1..3; 1..3; 1..3];
@cube[**[0; 0; *]] = 1, 2, 3;
@cube[**[0; 1; *]] = 4, 5, 6;
@cube[**[0; 2; *]] = 7, 8, 9;
@cube[**[1; 0; *]] = 10, 11, 12;
@cube[**[1; 1; *]] = 13, 14, 15;
@cube[**[1; 2; *]] = 16, 17, 18;
@cube[**[2; 0; *]] = 19, 20, 21;
@cube[**[2; 1; *]] = 22, 23, 24;
@cube[**[2; 2; *]] = 25, 26, 27;

or

my @cube[1..3; 1..3; 1..3];
@cube[**[0; 0; 0]] = 1;
@cube[**[0; 0; 1]] = 2;
@cube[**[0; 0; 2]] = 3;
@cube[**[0; 1; 0]] = 4;
@cube[**[0; 1; 1]] = 5;
@cube[**[0; 1; 2]] = 6;
...

where

say @cube[**[1; 1; 1]];

would be equivalent to

say @cube[0; 0; 0];

Do I have the general idea?

--
Jonathan "Dataweaver" Lang
```