dirac has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,
I want to make a transpose operation like Math::Matrix transpose() but with chars and with any number of rows/cols like:
A B C F G
u b 
1 T A R S 2 P
to:
A u 1
B b T
C   A
F   R
G   S
    2
    P
Is there a same intelligent way to do this? (without use any module ...)

Replies are listed 'Best First'.
Re: Transpose a matrix of chars
by BrowserUk (Patriarch) on Jul 04, 2005 at 09:13 UTC

    #! perl -slw use strict; use List::Util qw[ max ]; use Data::Dumper::SLC; my @cmat = ( [ qw[ A B C F G ] ], [ qw[ u b ] ], [ qw[ 1 T A R S 2 P] ], ); my @trans = map { my $index = $_; [ map{ $_->[ $index ] } @cmat ]; } 0 .. max map{ $#$_ } @cmat; Dump \@trans; __END__ P:\test>junk [ [ 'A', 'u', '1', ], [ 'B', 'b', 'T', ], [ 'C', undef, 'A', ], [ 'F', undef, 'R', ], [ 'G', undef, 'S', ], [ undef, undef, '2', ], [ undef, undef, 'P', ], ]

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
      Data::Dumper::SLC ?? What's that?

      And were you intentionally ignoring the request that modules not be used? I don't have a problem with that, but usually people say something like "modules are part of my toolkit, like it or lump it" or something more polite.

        Data::Dumper::SLC ?? What's that?

        It's my own module that produces better formatted output than Data::Dumper. As it is only used to test that the tranformation is correct, it doesn't affect the OPs use of the algorithm demonstrated.

        And were you intentionally ignoring the request that modules not be used?

        That leaves only my use of List::Util::max. Which, as it has been a part of the core for a while now, the possibility is that the OP would have access to it without an additional installation. If not, then the OP only has to ask here how write an equivalent function, or read the source of the pure perl version of L::U, if they don't know how to do that already.

        Feel free to consider the node for removal if this explaination doesn't satisfy.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
Re: Transpose a matrix of chars
by neniro (Priest) on Jul 04, 2005 at 09:28 UTC
    #!/usr/bin/perl use strict; use warnings; use List::Util qw/ max /; my @rows; push @rows, [split (/\s/, $_)] for (<DATA>); my $max_index = max map { scalar @$_ -1; } @rows; for my $r (0..$max_index) { for my $c (0..$#rows) { print $rows[$c]->[$r] || ' '; print ' '; } print "\n"; } __DATA__ A B C F G u b 1 T A R S 2 P
      I rewrite your code without use List::Util qw/ max /:
      #!/usr/bin/perl -w
      use strict;
      my @rows; 
      push @rows, [split (/\s/, $_)] while (<DATA>);
      my @nn = sort{$a <=> $b} map { @$_- 1 } @rows ;
      my $max_cols = pop @nn;
      
      for my $r (0..$max_cols) {
         for my $c (0..$#rows) { 
      		$_ = $rows[$c]->[$r] ;
      		print if defined;
         }
         print "\n";
      }
      
      
      __DATA__
      A B C F G
      u b 
      1 T A R S 2 P
      
      but I don't understand why this:
      my $max_cols = pop sort{$a <=> $b} map { @$_- 1 } @rows ;
      
      doesn't work and I must do this:
      my @nn = pop sort{$a <=> $b} map { @$_- 1 } @rows ;
      my $max_cols = pop @nn;
      
        pop only works on an array, not a list; try a list slice:
        my $max_col = (sort {$a <=> $b} map $#$_, @rows)[-1];
        though in this particular case, you can just reverse the sort and use a list assignment:
        my ($max_col) = sort {$b <=> $a} map $#$_, @rows;
        Nit: I think of "max_cols" as being maximum number of columns found, but you are wanting one less than that, the maximum column index, so I called it max_col instead. And I think @$_ - 1 is pretty ugly compared to the elegant $#$_ :)
        You could try:
        my $max_cols = pop @{[sort{$a <=> $b} map { @$_- 1 } @rows]};