http://qs321.pair.com?node_id=586569

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

I'm looking for a perl module to take a hash and format it suchly (this is sample data, don't be literal):
    Monday:   45       Tuesday: 09      Wednesday: 12
    Thursday: 98       Friday:  12      Saturday:  42
    Sunday:   55
Basically the idea is to take a list of data and, based on the current terminal's width, print that list in as many columns as will fit nicely (with some padding) on the screen. Any suggestions for a module to use? Text::Table only seem to handle one column nicely (it's meant for tables, not columns).

Replies are listed 'Best First'.
Re: Text Columns
by TheDamian (Vicar) on Nov 28, 2006 at 23:02 UTC
    Perl 6 formats aren't like Perl 5 formats. They're much more dynamic. And available in Perl 5. Try this:
    use List::Util qw< max >; my $terminal_cols = 80; # or whatever my $column_gap = 3; # or whatever my @display_items = map { "$_: $hash{$_}" } sort keys %hash; my $max_col_width = max map {length($_) + $column_gap} @display_items; my $column_count = $terminal_cols / $max_col_width; my $formatting = '{:[[{*}[[:}' x $column_count; use Perl6::Form; print form $formatting, (\@display_items) x $column_count;
Re: Text Columns
by Fletch (Bishop) on Nov 28, 2006 at 21:02 UTC

    Not a module, but there is an example in The Perl Cookbook on how to do something similar in chapter 4 (ch04/words if you have the example code tarball).

    Update: Linkyfied to example code.

Re: Text Columns
by swampyankee (Parson) on Nov 28, 2006 at 22:19 UTC

    I believe you would use Term::Cap to find the terminal's width. In some systems, it may be directly available as an environment variable (COLUMNS)

    You would then determine the length of your longest field (in your sample case, it would be the length of the string "Wednesday", plus 3 (for the colon and the two spaces that should follow a colon), plus 2 (for the length of '12' as a string), plus the padding you want between columns (you could use tabs, too). Figure out how many will fit (if you use tabs, which means you'll have to find out how wide a tab is in your output terminal. It's usually, but not always, 8). Build a format for sprintf or printf, and loop through the hash until finished. The lengths can be determined while the hash is being built. To force left-justification of a string, use something like "%-10s".

    emc

    At that time [1909] the chief engineer was almost always the chief test pilot as well. That had the fortunate result of eliminating poor engineering early in aviation.

    —Igor Sikorsky, reported in AOPA Pilot magazine February 2003.
      This is what I've basically done for now. There are some edge cases that this doesn't handle (I'll explain below). I'm sorta surprised that there is no perl module to do this already so maybe it's time I wrote one. I'd like to take this even further and be able to specify formats printf-like for the values.. It gets complicated quickly when I start thinking about fancy features...

        Sorry my assistance was too elementary. I spend a lot of programming time dealing with i/o issues (it's not uncommon for one of my non-Perl programs to have over 75% of the SLOC dealing with i/o), and writing format statements on the fly is one of my favorite -- and oldest -- tricks in handling i/o.

        emc

        At that time [1909] the chief engineer was almost always the chief test pilot as well. That had the fortunate result of eliminating poor engineering early in aviation.

        —Igor Sikorsky, reported in AOPA Pilot magazine February 2003.
      That's OK if all columns are to be of equal width, but if you want to have the maximum number of columns on the screen it gets much more complicated. I'm not even sure there exists a nice algoritm for it. I have a feeling it will get down to trial & error.

      CountZero

      "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Text Columns
by traveler (Parson) on Nov 28, 2006 at 22:54 UTC
    If you are on *nix, would it be good enough to open a pipe to column(1) for the standard output? If that wouldn't work, and/or you are not on *nix, maybe you could check the column(1) source code (as someone suggested doing with ls(1)).

    You might also check out Data::Show::Table.

    HTH, --traveler

A reply falls below the community's threshold of quality. You may see it by logging in.