Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Text Columns

by geoffeg (Acolyte)
on Nov 28, 2006 at 20:53 UTC ( #586569=perlquestion: print w/ replies, xml ) Need Help??
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).

Comment on Text Columns
Re: Text Columns
by Fletch (Chancellor) 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 clscott (Friar) on Nov 28, 2006 at 21:35 UTC

    Dude, put a little effort into it.

    perldoc -f format

    Did you even do a CPAN search or read the documentation?

    Read up on formats.

    Or Damian's take on format reform

    Possibly Damian and Larry's take on Perl 6 formats

    --
    Clayton

      "Dude," that's not even close to the question. The format function only sets up static format. If you don't know the sizes of your columns ahead of time, you're (mostly) stuck. Even perl6's formats are still largely stuck in the same mindset, despite being much more flexible. The OP is asking if there is anything out there that will determine how many columns are needed, and automagically set up a nice table. See the 'ls' command on unix for an example. Even 'dir' on Windows, with the /w flag, is close.

      For the most part, I've just made do with Text::Table. But it is an interesting problem. I would actually try using Text::Table, feeding it the screen width (which you can get with Term::Screen), and just keep adding columns until things don't fit. But that would definitely be slower than a more direct approach.

      If the OP is really interested, you might be able to find the source to the ls command and reimplement that algorithm in Perl. The implementation side probably will be easier in perl than C, it'll be the deciphering of the ls code that will be the hard part ;-)

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

Re: Text Columns
by TheDamian (Priest) 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;

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://586569]
Approved by Tanktalus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2014-09-20 23:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (163 votes), past polls