Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unpacking ArrayRef into X separate arguments

Tags:

perl

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.

like image 660
Hunter McMillen Avatar asked Feb 13 '23 02:02

Hunter McMillen


1 Answers

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];
    }
}
like image 121
amon Avatar answered Feb 28 '23 09:02

amon