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

After much unsucessful searching for a function/method to print a list in a format similar to the output of the unix 'dir' command, I've written this small script.
It turns, @array = qw/one two three four five six seven eight nine ten/
Into,
one two three four five six seven eight nine ten
I think the way I've done it must be quite inefficient, as it itterates through the entire array 3 times - firstly to get the max single length of the array entries - secondly to pad out shorter entries with space, up to the max length, thirdly to print it all out.
Can anyone offer me improvements, or suggest alternative ways of approaching this?
use strict; my @array = qw/one two three four five six seven eight nine ten/; my $cols = 3; my $max = 0; foreach (@array) { if (length >= $max) { $max = length $_; } } foreach (@array) { my $length = length $_; if ($length < $max) { $_ .= (' ' x ($max - $length)); } } while (@array) { unless (scalar @array >= $cols) { $cols = scalar @array; } print join(' ', splice(@array, 0, $cols) ), $/; }
My array will always be pre-sorted alphabetically.
This script doesn't print the list alphabetically down-ways, but I don't really need that anyway.

The array will actually be populated from searches on the 'linux.words' file, so it may contain many indices.
Thanks,
Carl

Replies are listed 'Best First'.
•Re: Printing an array in columns - improvements?
by merlyn (Sage) on Jul 18, 2002 at 15:12 UTC
    use strict; my @array = qw/one two three four five six seven eight nine ten/; my $cols = 3; my $max = 0; $max < length($_) and $max = length($_) for @array; my $output = ""; my @copy = @array; while (@copy) { $output .= join(" ", map sprintf("%-${max}s", $_), splice @copy, 0, +3)."\n"; } print $output;

    -- Randal L. Schwartz, Perl hacker

      Thanks!

      I'm just printed out the 'map' perldoc so I can figure out exactly what's happening.

      I found it interesting that you can
      splice(@array, 0, 3)
      Even if there's not 3 indices left in the @array.
Re: Printing an array in columns - improvements?
by Abigail-II (Bishop) on Jul 18, 2002 at 15:48 UTC
    #!/usr/bin/perl use strict; use warnings 'all'; my @array = qw/one two three four five six seven eight nine ten/; my $cols = 3; my $max = -1; $_ > $max && ($max = $_) for map {length} @array; while (@array) { print join " " => map {sprintf "%-${max}s" => $_} splice @array => 0, $cols; print "\n"; }

    Abigail

      Could I prevail upon you (or anyone) to explain the three uses of the => operator in your answer?

      I seen this a few times now, and have tried to understand it, but have to admit that I am completely foxed by it.

      Thanks.

        Well, its not from the horses mouth, but heres a quick explanation.

        Basically all Abigail-II is doing is conceptually breaking up the code by using the fat comma. Dont forget that semantically the => is equivelent to a comma (,) with the added nicety that if the item on the lhs is a bareword the bareword is automatically quoted.

        print join " " => map {sprintf "%-${max}s" => $_} splice @array => 0, $cols;
        is the same thing as
        print join " " , map {sprintf "%-${max}s", $_} splice @array, 0, $cols;
        as well as
        print join(" ",map {sprintf "%-${max}s",$_}splice(@array,0,$cols));
        The easiest to read is the first I think you'll agree. (although i dont know that i would have used a fat comma in the sprintf() call but whatever ;-)

        Yves / DeMerphq
        ---
        Writing a good benchmark isnt as easy as it might look.

Re: Printing an array in columns - improvements?
by Fletch (Bishop) on Jul 18, 2002 at 15:13 UTC

    If you have a copy of the Perl Cookbook (isbn:1565922433), it has a recipie in one of the earlier chapters (don't have it handy, and a search through the code isn't turning up anything immediately) for formating things in columns similar to the way ls does (given n columns of characters, show the items from @foo in the fewest number of columns of items).

(dooberwah) Re: Printing an array in columns - improvements?
by dooberwah (Pilgrim) on Jul 18, 2002 at 15:32 UTC
    Here's my attempt at the same problem.

    #!/usr/local/bin/perl -w use strict; use POSIX; my @array = qw/one two three four five six seven eight nine ten/; my $cols = 3; my $tabs = 1; foreach my $value ( @array ) { my $foo = ceil( length( $value ) / 8 ); $tabs = $foo if $tabs < $foo; } while ( @array ) { for ( 1 .. $cols ) { my $slice = shift @array; print $slice if defined $slice; print "\t" for 1 .. $tabs; } print "\n"; }

    -Ben Jacobs