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

Hi everyone,
I have a problem with some code tweeking. The problem I have is that the columns are all messed up.

This is output I have

02:17 02:40 02:46 02:59 Apples 0 0 0 0 Grapes 7 7 7 7 bricks 0 0 0 0 TUBELIGHS 282 271 265 257 TOTAL 334 320 312 303

This is the part of the code I am using:

printf "%${lenght_frt}s ", " "; foreach (sort keys %date) { printf "%-${lenght_date}s ", $_; } print "\n"; foreach (sort keys %obj) { printf "%-${lenght_frt}s ", $_; for( my $i = 0; $i <= $#date; $i++) { if(exists($count{$_}->{$date[$i]})) { print " " x ($lenght_date), $count{$_}->{$date[$i]}; } } print "\n"; } close (FH); print "\n"; printf "%-${lenght_frt}s ", " TOTAL "; print map { sprintf "%7d", $_ }@tasks; print "\n"; }

How can I correct the code so that my output is clean like:

02:17 02:40 02:46 02:59 Apples 0 0 0 0 Grapes 7 7 7 7 bricks 0 0 0 0 TUBELIGHS 282 271 265 257 TOTAL 334 320 312 303

GREATEFULLY

Code tags and formatting added by GrandFather

Replies are listed 'Best First'.
Re: arrange columns
by madbombX (Hermit) on Jul 29, 2006 at 07:10 UTC
    Have you considered using Perl's builtin formatting mechanisms? perlform. That seems to me that that's what your goal is.

    Potentially something like this would work for you:

    format STDOUT_TOP = @<<<<<<<<< @<<<<<<<<< @<<<<<<<<< @<<<<<<<<< $time[0], $time[1], $time[2], $time[3], . format STDOUT = @<<<<<<<<< @### @### @### @### $type, $val1, $val2, $val3, $val4 . $~ = "STDOUT_TOP"; write;

    Eric

Re: arrange columns
by fmerges (Chaplain) on Jul 29, 2006 at 07:34 UTC

    Hi,

    If you have problem with the limitations of the standard perl format you can also use Perl6::Form.

    Regards,

    fmerges at irc.freenode.net
      I would be stronger on this. If you are going to use formatting functions beyond printf(), use Perl6::Form. Those who are learning this area should not learn "format"; "format" will force them to learn many idiosyncracies that they will then have to un-learn when "form" becomes the standard in perl6. It will also generate code that fewer and fewer people understatnd over the years. Perl6::Form is no harder to learn. In many ways it's easier to learn if you're doing simple things, and it leaves you with more flexibility in your code, since formatting is not tied to the action of sending output.

      I intend no disrespect to "format". It was a valuable feature which has served my software well. The new "form" has learned from it and brought us a much cleaner implementation. We should use it for any new collection of formatting code, and we should direct those who are new to the area to it, so they don't lean something that will soon be fading.

      Addendum: I can think of two reasons why you might want to continue to use the Perl5 "format" in writing new code:

      • To maintain consistency with a large body of code that already uses "format".
      • For small things that must run in and environment where it's difficult to install modules like Perl6::Format.
Re: arrange columns
by liverpole (Monsignor) on Jul 29, 2006 at 15:22 UTC
    It looks like the format of your data in the final section "How can I correct the code so that my output is clean" is still fairly garbled.  I'll assume that you wanted things lined up like:
    02:17 02:40 02:46 02:59 Apples 0 0 0 0 Grapes 7 7 7 7 bricks 0 0 0 0 TUBELIGHS 282 271 265 257 TOTAL 289 278 272 264

    If you want to do this using good ol' printf, which nobody has suggested (but was part of your original post), here is how I would do it:

    #!/usr/bin/perl -w # Strict use strict; use warnings; # Assign variables my $plabels = [ '02:17', '02:40', '02:46', '02:59' ]; my $pcounts = { 'Apples' => [ 0, 0, 0, 0, ], 'Grapes' => [ 7, 7, 7, 7, ], 'bricks' => [ 0, 0, 0, 0, ], 'TUBELIGHS' => [ 282, 271, 265, 257, ], }; my $p_ordered = [ qw( Apples Grapes bricks TUBELIGHS ) ]; my $ncols = 4; # Or $ncols = scalar @{$pcounts->{$p_ordered->[0]} +}; # Calculate totals my $pTOTAL = [ ]; foreach my $key (keys %$pcounts) { map { $pTOTAL->[$_] += $pcounts->{$key}->[$_] } (0..$ncols-1); } # Main program print_row("", $plabels, " %7.7s"); map { print_row($_, $pcounts->{$_}, " %7d") } @$p_ordered; print "\n"; print_row("TOTAL", $pTOTAL, " %7d"); # Subroutines sub print_row { my ($label, $pvalues, $format) = @_; printf " %-12.12s", $label; map { printf $format, $_ } @$pvalues; print "\n"; }

    Note that by using a subroutine print_row, you achieve a couple of things.  First, it greatly simplifies the main program down to just several lines.  And secondly, it lets you change the width of each item in the output, just by changing the format passed to the subroutine (eg. change " %7.7s" to " %-7.7s" to left-justify the labels, or change " %7.7s" and " %7d" to " %8.8s" and " %8d" respectively, to increase the width of each item to 8 characters).

    PS. What the heck is a "TUBELIGH"? :)


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
      It looks like the format of your data in the final section "How can I correct the code so that my output is clean" is still fairly garbled. I'll assume that you wanted things lined up like:
      If you download the code and view it with tab width 8, it will show up correctly. It doesn't in the node as perlmonks has a simpler idea about displaying tab characterss in code tags than is required here.
Re: arrange columns
by GrandFather (Saint) on Jul 29, 2006 at 05:00 UTC

    How about posting something that can actually be run to generate the table you show. I started out trying to infer what the various variables contain and what type they were, but gave up after not being able to reconcile sort keys %date and $i <= $#date.


    DWIM is Perl's answer to Gödel
Re: arrange columns
by Ieronim (Friar) on Jul 29, 2006 at 11:29 UTC
    If you need to generate text tables, use Text::Table :) Simply, yeah? CPAN is your friend.

         s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print
Re: arrange columns
by jdporter (Paladin) on Jul 31, 2006 at 14:45 UTC

    This line:

    print " " x ($lenght_date), $count{$_}->{$date[$i]};

    Should be using printf, i.e. something like:

    printf "%${lenght_date}s ", $count{$_}->{$date[$i]};

    Similarly,

    print map { sprintf "%7d", $_ } @tasks;

    Should be written as:

    print map { sprintf "%${lenght_date}s " } @tasks;

    In other words, use the same formatting technique, with the same widths, for every row of the output.

    We're building the house of the future together.