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:
dir1: +[ dir2 ] item4 item8 item1 item5 item9 item2 item6 item3 item7 dir2: item1 itemwithareallyreallystupidlylongname4 item2 item5 item3
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__
mkmcconn
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Ways to print lists into columns
by BrowserUk (Patriarch) on Aug 14, 2002 at 23:07 UTC |