Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Ways to print lists into columns

by mkmcconn (Chaplain)
on Aug 14, 2002 at 22:58 UTC ( #190259=perlquestion: print w/replies, xml ) Need Help??

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

This is a code clinic question. I'm trying to polish a script that prints a directory tree in a format that's roughly equivalent to 'ls *'. For example:

+[ dir2 ]      item4        item8
item1          item5        item9     
item2          item6         
item3          item7         

item1 itemwithareallyreallystupidlylongname4
item2 item5

What I've written is more complicated than I suspect it should be; and, it doesn't quite do all that I want. How can I improve it?

The example below shows the four subroutines that do the work. I apologize for how much code there is, but I thought it might be helpful to give you a working program to play with.

build_list() collects the directory contents. distribute_evenly() divides these lists into roughly even-sized arrays using maxsize() to determine the number of columns, if $cols is not set. printto_columns() prints out the list, padding the columns to fill the width of the page or screen.

I don't know: it just looks clumsy, to me. I'm particularly unhappy with printto_columns(), and although distribute_evenly is a marvel of brevity (thanks to I0), I'm not sure that I'm taking the best approach, here (see the '*1.10' in distribute_evenly()? - there must be a more proper way to do that). May I bother you for some ideas of better ways to do each of these various tasks?

Thanks in advance for your opinions...

...I won't be able to read them until next week.

#!/usr/bin/perl -w use strict; use File::Find; my $breakpage = 0; my $short = 1; my $cols = 0; my $width = 70; my $underchar = "\x{00AF}"; # or try "\x{007E}" (tilde) my $list = build_list(\@ARGV); printto_columns($list); sub build_list{ my %gather_list; my $directory_list = shift; for my $topdir (sort(@$directory_list)){ print "Listing $topdir\n"; $topdir =~ tr~\\~/~; find(\&{sub{ unless (defined $gather_list{$File::Find::dir}){ + ($gather_list{$File::Find::dir}) = map{ [ m{([^/]+)$} ] } "$File::Find::dir" ; } return if m{\.$}; my $item = -d $_ ? "+[ $_ ]" : $_; push @{$gather_list{$File::Find::dir}}, $item; }}, $topdir); }; return \%gather_list; } sub printto_columns{ my $hashoflists = shift; for my $key_hdr (sort keys %$hashoflists){ my $short_hdr = shift @{$hashoflists->{$key_hdr}}; # assemble a header for each list my $header = ""; $header .= "\f" if $breakpage; if ($short){ $header .= "\n$short_hdr:\n" . ($underchar x (length $short_hdr)) . "\n"; }else{ my ($path_hdr) = $key_hdr; $path_hdr =~ tr{/}{\\} if $^O =~ /Win/i; $header .= "\n$path_hdr\n" . ($underchar x (length $path_hdr)) . "\n" ; } print $header unless $header eq "\f"; # split to columns called for, here. my ($grid,$columns) = distribute_evenly($hashoflists->{$key_h +dr}) ; my $pad_to_page = int($width / $columns); for my $x_coord (0..scalar @{$grid->[0]}){ my $row = ""; for my $y_coord (0..$columns-1){ my $cell = defined $grid->[$y_coord]->[$x_coord] ? + $grid->[$y_coord]->[$x_coord] : ""; my $spacer = $pad_to_page - length ($cell); $spacer = 1 if $spacer <= 0; my $pad_col = $y_coord < $columns-1 ? "\x{0020}" x $s +pacer : ""; $row .= length ($row) + length ($cell) > $width + ? "\n". ("\x{0020}" x ($width - (length $cell)) +)."$cell\n" : ${cell}.${pad_col}; } print "$row\n"; } } } sub distribute_evenly{ my $chunks = shift; my $bowls = $cols || int( $width / (maxsize($chunks)*1. +10) ) ; my @alphabet_soup = sort @$chunks; my @ladels = map {int((@alphabet_soup)*$_/$bowls)} -$bow +ls..0; ([map {[@alphabet_soup[$ladels[$_-1]..($ladels[$_]-1)]]} 1..$bowls], +$bowls); } sub maxsize{ my $maxsize = 0; my $to_measure = shift; for (@$to_measure){ my $thissize = length; $maxsize = $thissize unless $maxsize > $thissize; } $maxsize ; } __END__


Replies are listed 'Best First'.
Re: Ways to print lists into columns
by BrowserUk (Patriarch) on Aug 14, 2002 at 23:07 UTC

    Take a look at:153602 (and others)

    Type "print columns" into the search box at the top of the screen.

    Having had a /msg conversation with mkmcconn, I realised that he is writing this as a Learning Perl exercise and wants critque of his code, rather than a "module solution".

    On that basis, I'll let someone with greater expertise than me offer the advice.

    It might still be worth downloading the source of some of the module solutions described elsewhere and take a look how they do this. Though I appreciate that the code in some of the modules can be all but indecipherable to non- or only-slightly Perlish eyes:)

    What's this about a "crooked mitre"? I'm good at woodwork!

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://190259]
Approved by Aristotle
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (5)
As of 2023-01-28 07:39 GMT
Find Nodes?
    Voting Booth?

    No recent polls found