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 thenI've removed the purely formatting part (
|
) of the string which is the value ofname
. 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