I can make a shaped (fixed-size) array:
my @array[3;3] = (
< 1 2 3 >,
< 4 5 6 >,
< 7 8 9 >
);
say @array; # [[1 2 3] [4 5 6] [7 8 9]]
say @array[1;1]; # 5
How can I slice this to get any particular column or diagonal that I want (rows are easy)?
How do I turn a list of the indices in each dimension into the right thing to put in the square braces?
And, surely there's some fancy syntax that would keep me from doing something complicated:
my @diagonal = gather {
my @ends = @array.shape.map: { (0 ..^ $^a).List };
for [Z] @ends {
take @array[ $_ ] # how do I make that $_[0];$_[1];...
};
}
How can I slice this to get any particular column or diagonal that I want?
As far as I know, you can't currently use slice syntax with shaped arrays (notwithstanding your "(rows are easy)" comment which confuses me per my comment on your post).
The obvious solution is to drop the shape and use slice syntax:
my @array = ( < 1 2 3 >, < 4 5 6 >, < 7 8 9 > );
say @array[1]; # 4 5 6 (second row)
say @array[1;*]; # same
say @array[*;1]; # 2 5 8 (second column)
If you wanted to retain the bounds-checking safety of using a shaped array (and/or the C array compatibility of a shaped native array if I'm right that's a thing) then you'd presumably have to keep two copies of the array around, using one to retain the desired aspect of shaped arrays, the other to slice.
How do I turn a list of the indices in each dimension into the right thing to put in the square braces?
Each dimensional slice before the final leaf one must be separated from the next by a ;
.
I'm not yet clear on whether that's because the ;
is a statement separator (within the subscript) or a list-of-list indicator, nor how to programmatically turn a list of indices into that form. (Investigation continues.)
And, surely there's some fancy syntax that would keep me from doing something complicated [for a diagonal slice]:
say @array[*;{$++}]; # 1 5 9 (diagonal)
The first ;
separated field in the [...]
array subscript corresponds to the first dimension in the array, i.e. the rows in the array.
Specifying *
means you want to include all rows rather than specify the specific row(s).
The last field corresponds to the leaves of the subscript, the actual elements to be accessed.
I first tried just $++
rather than {$++}
but that gave me column zero for all elements presumably because the language/roast and/or Rakudo only evaluates a scalar index value once per call of the [...]
subscript operator.
Then I reasoned that if an index is Callable it'll be called and it might be called once per row. And that worked.
I think that corresponds to this code in Rakudo.
At first glance this appears to mean you can't use a Callable
to calculate a leaf slice and I note that the roast'd slicing for "calculated indices" doesn't include use of a Callable
. Perhaps I'm just not looking at it right.
You probably have seen that that returns a not yet implemented error (which was inserted to solve this bug;
Partially dimensioned views of shaped arrays not yet implemented. Sorry.
In this case, it might be better to just unshape the array and use a more traditional approach:
use v6;
my @array = (
< 1 2 3 >,
< 4 5 6 >,
< 7 8 9 >
);
my @diagonal = gather {
my @ends = ((0,0),(1,1),(2,2));
for @ends -> @indices {
take @array[ @indices[0] ][@indices[1]];
};
}
say @diagonal;
By looking at the synopsis on the subject, I would say that approach is not really specified. So when all is said and done, you will probably have to use either EVAL
or macros (when they are eventually implemented, of course... )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With