in reply to How to transpose lines faster?
Here's my nomination. I haven't done any Benchmark-ing, but the minimal computation done in the inmost for-loop gives me hope that it will have a chance.
use warnings; use strict; use Test::More 'no_plan'; use Test::NoWarnings; # use Data::Dump qw(dd); # use constant DEBUG => 0; # use constant { # DBPR_1 => 0 && DEBUG, # DBPR_2 => 0 && DEBUG, # }; BEGIN { # ASSUME: # > no element of a matrix row/string will ever be an empty # string. chop()-ing does not work with empty strings! # > all array/matrix elements/rows have equal string lengths. use constant M_5x4 => qw(abcde fghij klmno pqrst); # input arr +ay use constant T_5x4 => qw(afkp bglq chmr dins ejot); # transpose +d output use constant M_5x5 => qw(abcde fghij klmno pqrst uvwxy); use constant T_5x5 => qw(afkpu bglqv chmrw dinsx ejoty); use constant M_5x6 => qw(abcde fghij klmno pqrst uvwxy zABCD); use constant T_5x6 => qw(afkpuz bglqvA chmrwB dinsxC ejotyD); use constant M_6x5 => qw(abcdef ghijkl mnopqr stuvwx yzABCD); use constant T_6x5 => qw(agmsy bhntz ciouA djpvB ekqwC flrxD); use constant M_6x6 => qw(abcdef ghijkl mnopqr stuvwx yzABCD EFGHIJ); use constant T_6x6 => qw(agmsyE bhntzF ciouAG djpvBH ekqwCI flrxDJ); use constant M_6x7 => qw(abcdef ghijkl mnopqr stuvwx yzABCD EFG +HIJ KLMNOP); use constant T_6x7 => qw(agmsyEK bhntzFL ciouAGM djpvBHN ekqwCIO flr +xDJP); use constant M_0x0 => qw(); use constant T_0x0 => qw(); use constant M_1x1 => qw(a); use constant T_1x1 => qw(a); use constant M_2x1 => qw(ab); use constant T_2x1 => qw(a b); use constant M_1x2 => qw(a b); use constant T_1x2 => qw(ab); # this hash is private to test_set() function. my %test_sets = ( # define fresh test set generators '0x0' => sub { return [ M_0x0 ], [ T_0x0 ] }, '1x1' => sub { return [ M_1x1 ], [ T_1x1 ] }, '2x1' => sub { return [ M_2x1 ], [ T_2x1 ] }, '1x2' => sub { return [ M_1x2 ], [ T_1x2 ] }, '5x4' => sub { return [ M_5x4 ], [ T_5x4 ] }, '5x5' => sub { return [ M_5x5 ], [ T_5x5 ] }, '5x6' => sub { return [ M_5x6 ], [ T_5x6 ] }, '6x5' => sub { return [ M_6x5 ], [ T_6x5 ] }, '6x6' => sub { return [ M_6x6 ], [ T_6x6 ] }, '6x7' => sub { return [ M_6x7 ], [ T_6x7 ] }, ); sub test_set { # generate fresh test set my ($set, # test set tag string ) = @_; return $test_sets{$set} ? $test_sets{$set} ->() : die "non-existent test set: '$set'" ; } } # end BEGIN block -- test set generator use constant TEST_1 => ( \'degenerate case(s)', qw(0x0), \'corner cases', qw(1x1 2x1 1x2), \'common cases', qw(5x4 5x5 5x6), qw(6x5 6x6 6x7), ); FUNT: for my $func_name ( qw(AnomalousMonk_1) ) { note "\n=== testing $func_name() ===\n\n"; *transpose = do { no strict 'refs'; *$func_name; }; VECTOR: for my $set (TEST_1) { if (ref $set) { note $$set; next VECTOR; } my ($ar_input, $ar_expected) = test_set($set); my $ar_input_copy = [ @$ar_input ]; # shallow copy is_deeply transpose($ar_input), $ar_expected, "'$set' transposed"; is_deeply transpose($ar_expected), $ar_input, "'$set' reflexive"; is_deeply $ar_input, $ar_input_copy, "'$set' non-destructive"; } # end for VECTOR } # end for FUNT done_testing; exit; # functions under test ############################################# sub AnomalousMonk_1 { my ($ar_matrix, # ref. to array of strings: matrix to transpose ) = @_; # ASSUME: all array/matrix elements have equal string lengths. my $r_all = reverse @$ar_matrix; my $i_max = @$ar_matrix && length($ar_matrix->[0]) - 1; my @transposed; for (0 .. $#$ar_matrix) { for (0 .. $i_max) { $transposed[$_] .= chop $r_all; } } return \@transposed; }
Update: It just occurred to me that pre-extending the @transposed array might squeeze out a few more microseconds of performance. In the AnomalousMonk_1() function, change the
my @transposed;
statement to
my @transposed;
$#transposed = $i_max - 1;
(tested | tested for correctness, but again, no benchmarking for speed).
Give a man a fish: <%-{-{-{-<
|
|---|