Home > other >  Print size and count in adjacent rather than in new line in Perl
Print size and count in adjacent rather than in new line in Perl

Time:08-01

I have written a script which will fetch values from db and store it in the hash called total_hash. To make question simpler I have hard coded the hash here.

Next step I need to display these hash content in table format, so used a below logic to display it on the screen.

#!/usr/bin/perl

use strict; use warnings;
use Data::Dumper;

my $method_total = 1;
my $method_a = 1;
my $method_b = 1;
my $method_sync = 1;

my %total_hash = (
  'Method_Combine' => {
              'flag' => 1,
              'count' => 27,
              'name' => '| Method TOTAL',
              'size' => 270
            },
  'Method_A' => {
                'count' => 7,
                'flag' => 1,
                'name' => '| Method A',
                'size' => 70
              },
  'Method_B' => {
                'count' => 20,
                'flag' => 1,
                'size' => 200,
                'name' => '| Method B'
              },
  'Method_Sync' => {
               'name' => '| Method Sync',
               'size' => 300,
               'flag' => 1,
               'count' => 30
             }
);
#print "total_hash:\n".Dumper(\%total_hash);

printReport(\%total_hash);

sub printReport {
    my $hash = shift;
    my $string1 = "";
    my $string2 = "";
    my $string3 = "";
    my $append_data = "";
    my $length = 20;
    my $total_length = $length * ($method_sync   $method_a   $method_b   $method_total)   1;
    my @columns = ('Method_Sync','Method_A','Method_B','Method_Combine');

    foreach my $key (@columns) {
        if ($hash->{$key}->{flag}) {
            $append_data = sprintf("%-".$length."s",$hash->{$key}->{name});
            $string1 .= $append_data;
            $append_data = sprintf("%-".$length."s","| ".$hash->{$key}->{size}." Bytes");
            $string2 .= $append_data;
            $append_data = sprintf("%-".$length."s","| ".$hash->{$key}->{count});
            $string3 .= $append_data;
        }
    }
    print("Report:\n\n");
    print "-" x $total_length."\n";
    print $string1 . "|\n";
    print "-" x $total_length."\n";
    print $string2 . "|\n";
    print "-" x $total_length."\n";
    print $string3 . "|\n";
    print "-" x $total_length."\n";
}

Here content is getting printing like below (actual ouput):

---------------------------------------------------------------------------------
| Method Sync       | Method A          | Method B          | Method TOTAL      |
---------------------------------------------------------------------------------
| 300 Bytes         | 70 Bytes          | 200 Bytes         | 270 Bytes         |
---------------------------------------------------------------------------------
| 30                | 7                 | 20                | 10                |
---------------------------------------------------------------------------------

I want it to be printed like below (expected result):

-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| Method Sync       | Method Sync Count | Method A          | Method A Count    | Method B          | Method B Count    | Method TOTAL      | Method TOTAL Count|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| 300 Bytes         | 30                | 70 Bytes          | 7                 | 200 Bytes         | 20                | 270 Bytes         | 27                |
---------------------------------------------------------------------------------------------------------------------------------------------------------------

Each of the Methods Size and Count should be printed adjacent side rather than printing in the new line for the count. How to do that?

CodePudding user response:

Here is one way to format it for display as desired.

To align the key names with their size/count prepare columns with name, value(s), and width (maximum between the name and the corresponding value). Then lay them out: first the line with all headers then the one with their corresponding data, both using their column's width

use warnings;
use strict;
use feature 'say';
#use Data::Dump qw(dd);
use List::Util qw(max);

my %total_hash = (
    'Method_Combine' => 
        { 'count' => 27, 'name' => 'Method TOTAL', 'size' => 270 },
    'Method_A' =>       
        { 'count' => 7,  'name' => 'Method A',     'size' => 70 },
    'Method_B' =>       
        { 'count' => 20, 'name' => 'Method B',     'size' => 200 },
    'Method_Sync' =>    
        { 'count' => 30, 'name' => 'Method Sync',  'size' => 300 }
);

my @keys = qw(Method_Sync Method_A Method_B Method_Combine);  # ordered

my @cols;
for (@keys) { 
    push @cols, { 
        header => $total_hash{$_}{name}, 
        data   => $total_hash{$_}{size} . ' Bytes',
        width  => max map { length } 
            ($total_hash{$_}{name}, $total_hash{$_}{size} . ' Bytes')
    };
    push @cols, { 
        header => $total_hash{$_}{name} . ' ' . 'Count',
        data   => $total_hash{$_}{count},
        width  => max map { length } 
            ($total_hash{$_}{name} . ' ' . 'Count', $total_hash{$_}{count})
    };
}
# dd \@cols;  # just to see it

my $hdr_str = '| ' . join(' | ', 
    map { sprintf "%-*s", $_->{width}, $_->{header} } @cols) . ' |';
my $dat_str = '| ' . join(' | ', 
    map { sprintf "%-*s", $_->{width}, $_->{data} }  @cols) . ' |';
my $sep = '-' x length $hdr_str;

say for $sep, $hdr_str, $sep, $dat_str, $sep;

Prints

--------------------------------------------------------------------------------------------------------------------------------
| Method Sync | Method Sync Count | Method A | Method A Count |  Method B | Method B Count | Method TOTAL | Method TOTAL Count |
--------------------------------------------------------------------------------------------------------------------------------
| 300 Bytes   | 30                | 70 Bytes | 7              | 200 Bytes | 20             | 270 Bytes    | 27                 |
--------------------------------------------------------------------------------------------------------------------------------

I've changed the hash and requirements a little

  • I formatted columns to be each as wide as needed, not all the same. That only requires more work and if you want them all to be the same width it's easier: find the maximal width of all names and values and use that everywhere. No need for width element then

  • I've removed the purely formatting part (| ) of the string which is the value of name. While I can see the rationale for having it there, it is generally better to separate data from format; those bars are easily added as needed (or not, or something else can be)

  • I've also removed a key/value which is unused here (flag => 1), for easier viewing

There are of course libraries for this, once we've prepared header and data columns to pretty-print, like text-templates and various modules for formatted/tabular print of text. Then there is also Perl's own format, and better yet Perl6::Form. But sprintf is adequate here.

A note on style. Experience shows that extra formatting elements in tables generally end up distracting rather than helping. It is usually enough to separate a header, and have sufficient spacing between columns. Other than that, less is more for clarity. Perhaps consider

 Method Sync    Method Sync Count    Method A    Method A Count   
----------------------------------------------------------------    ...
 300 Bytes      30                   70 Bytes    7               
  • Related