Given an arrayref that contains other arrayrefs, is it possible to zip the nested arrayrefs together using the zip function from List::MoreUtils
?
For instance given this arrayref:
my $matrix = [
[qw( 1 2 3 4)],
[qw( 5 6 7 8)],
[qw( 9 10 11 12)],
[qw(13 14 15 16)],
[qw(17 18 19 20)],
];
I would like to zip each row together so I can get the transpose. Expected output:
[
[qw(1 5 9 13 17)],
[qw(2 6 10 14 18)],
[qw(3 7 11 15 19)],
[qw(4 8 12 16 20)],
];
My initial attempts were:
# I had hoped the function would unpack the arguments
zip @$matrix;
# ERROR: Not enough arguments for List::MoreUtils::mesh at spiral.pl line 17
# I thought this slice would suffice to unpack them
zip @$matrix[1..scalar @$matrix-1];
# ERROR: Type of arg 1 to List::MoreUtils::mesh must be array (not array slice)
I am sure there is a way to do this elegantly, I am just not seeing it. Any help would be appreciated.
The zip
function is extremely annoying because it uses a (\@\@;\@\@\@...)
prototype or something insane like that. You'd have to do an ampersand-call to override the prototype: &zip(@$matrix)
.
However, you are trying to transpose the matrix, not to zip
it (which would produce a continuous list like
[1, 5, 9, 13, 17, 2, 6, 10, 14, 18, 3, 7, 11, 15, 19, 4, 8, 12, 16, 20]
We could use an natatime
iterator in conjunction with zip
:
my $iter = natatime @$matrix, &zip(@$matrix);
my @transposed;
while (my @column = $iter->()) {
push @transposed, \@column;
}
which works, but this is severely overthinking the problem. Let's just swap indices:
my $transposed = [];
for my $i (0 .. $#$matrix) {
for my $j (0 .. $#{ $matrix->[0] }) {
$transposed->[$j][$i] = $matrix->[$i][$j];
}
}
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