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

In reply to Ways to print lists into columns by mkmcconn

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.