I had a need to print the values of an array in vertical columns.

Input array:

one two three four five six seven eight nine ten

Output:

t s e h f f e i n o t r o i s v g i t n w e u v i e h n e e o e r e x n t e n

Here's the code I came up with to do it...

use strict; my @w_rows = qw(one two three four five six seven eight n +ine ten); # Rows rows_to_columns(\@w_rows, " ", 1); ############################################################ # Function: rows_to_columns # Purpose: Vertically print the input array # Example: rows_to_columns(\@array[,$pad[,$justify]]); ############################################################ sub rows_to_columns { my $r_rows = $_[0]; # Ref to input array my $w_pad = $_[1] || ' '; # Spacing between columns my $s_justify = $_[2] || 0; # Justify 0=top, 1=bottom return 0 unless (ref($r_rows) eq "ARRAY"); my @w_rows = @$r_rows; my %w_columns = (); my %w_col_rows = (); my $w_row_ix = 0; my $w_col_ix = 0; my $l_max_row = 0; my $w_row = ''; # Find the longest array element ($l_max_row) $w_row_ix = map { $l_max_row= (length($_) > $l_max_row) ? length($_) : $l_max_row; } @w_rows; ##################################### # Process input array ##################################### for ( $w_row_ix = 0; $w_row_ix <= $#w_rows; $w_row_ix++ ) { $w_row = ($s_justify) ? ' ' x ($l_max_row - length($w_rows[$w_row_ix +])) . $w_rows[$w_row_ix] : $w_rows[$w_row_ix] . ' ' x ($l_max_row - len +gth($w_rows[$w_row_ix])) ; # print "$w_row\n"; ################### # Reformat->columns ################### for ( $w_col_ix = 0; $w_col_ix < $l_max_row; $w_col_ix++ ) { my $w_char = substr($w_row,$w_col_ix,1); $w_columns{$w_col_ix} = "$w_columns{$w_col_ix}${w_pad}${w_ +char}"; } } ##################################### # Print input array - vertically ##################################### for my $key ( sort { $a <=> $b } keys %w_columns ) { print "$w_columns{$key}\n"; } return 1; }

Comments and constructive suggestions are welcome :)

Replies are listed 'Best First'.
Re: Print array vertically (in columns)
by liverpole (Monsignor) on Sep 02, 2009 at 00:09 UTC
    An interesting solution to an interesting problem.

    I noticed you didn't use warnings; putting them in gives this:

    Use of uninitialized value in concatenation (.) or string at x.pl line + 47. Use of uninitialized value in concatenation (.) or string at x.pl line + 47. ...
    But you can fix it as easily as changing the line:
    $w_columns{$w_col_ix} = "$w_columns{$w_col_ix}${w_pad}${w_char}";

    to:

    $w_columns{$w_col_ix} .= "${w_pad}${w_char}";

    Then, for fun, I tried golfing it.  Assuming the second parameter will almost always be spaces, I changed it from a string to the number of spaces (but left the default at 2).

    Here's my result:

    use strict; use warnings; my $a_rows = [qw[one two three four five six seven eight nine ten]]; my $npad = 4; my $justify = 1; rows_to_cols($a_rows, $npad, $justify); sub rows_to_cols { my ($x, $p, $j) = @_; my $m = 0; map { $m = length $_ if $m < length $_ } @$x; ($j||0) && map { $_ = sprintf "%*s", $m, $_ } @$x; @_ = map { ($")x($p||2),$_ } @$x; map { map { print substr($_, 0, 1, "") || $" } @_; print $/ } 1..$ +m }

    And here's what's happening:


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/

      Brilliant! This is what I love about PerlMonks: people sharing, improving and (in my case) learning! Although I've been coding in perl for a while now, I sometimes get stuck in the rut of doing things the same way. And, then I look at someone else's solution to a similar issue, and WHAM! -- I never thought of doing it that way -- that's WAY better.

      So, thanks for taking the time to play around with my code. I had to stare at a couple of your modified statements awhile, to make sure I understood how you did it in so little code (your cheater block helped).

Re: Print array vertically (in columns)
by bv (Friar) on Sep 04, 2009 at 17:17 UTC

    Nice solution! We ran into this issue doing a header for a grid of open ports on network systems (input generated by nmap). Since we knew the max length of our input (5 digits for tcp ports), we use this solution:

    sub numerically { $a <=> $b }; my @portsorted = sort numerically keys %ports; my @header; for (@portsorted) { my @portchars = split //, $_ . ' ' x (5 - length()); for ( 0 .. 4 ) { push @{$header[$_]}, $portchars[$_]; } } for (@header) { print "\t\t ", join('|',@{$_}), "\n"; } print "IPs\t\t ", '_|' x scalar(@portsorted), "\n"; __END__ outputs this (tabs notwithstanding): 2|8|1|1|4|4|9 2|0|1|3|4|4|3 | |1|9|3|5|8 | | | | | | | | | | | | IPs _|_|_|_|_|_|_|

    Obviously yours has more appeal as a general solution, since we don't have options for alignment, spacing, or so forth.

    print pack("A25",pack("V*",map{1919242272+$_}(34481450,-49737472,6228,0,-285028276,6979,-1380265972)))
Re: Print array vertically (in columns)
by stonecolddevin (Parson) on Sep 18, 2009 at 21:56 UTC

    Also, check out Text::SimpleTable.  If you've used Catalyst at all, that's what generates the data in tabular form for the development server.  It's pretty neat, easy to use and rather configurable.

    mtfpny