I have written a script which will fetch data from db with certain condition and store it in the hash. I need these stored hash content to show in the tabular format.
Right now I have all the data which should be shown in the table is there in the hash called %hash
.
I need to display the content of the hash in console in tabular format.
Below is my script:
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper;
my %hash = (
'2022-08-04' => {
'Method 1' => {
'Count' => 50,
'Size' => '10 MB'
},
'Method 2' => {
'Count' => 40,
'Size' => '5 MB'
}
},
'2022-08-05' => {
'Method 1' => {
'Count' => 30,
'Size' => '3 MB'
},
'Method 2' => {
'Size' => '50 MB',
'Count' => '100'
}
}
);
my @cols;
my @keys = ('Method 1', 'Method 2');
foreach my $date (sort keys %hash){
foreach my $method (@keys) {
push (@recs, { date => $date, size => $hash{$date}{$method}{'Size'}, count => $hash{$date}{$method}{'Count'}});
}
}
print "cols:\n".Dumper(\@cols)."\n";
my $line1 = '| ' . join(' | ', map { sprintf "%-*s", 20, $_->{date} } @cols) . ' |';
my $line2 = '| ' . join(' | ', map { sprintf "%-*s", 20, $_->{size} } @cols) . ' |';
my $line3 = '| ' . join(' | ', map { sprintf "%-*s", 20, $_->{count} } @cols) . ' |';
print $line1."\n";
print $line2."\n";
print $line3."\n";
Current Result:
| 2022-08-04 | 2022-08-04 | 2022-08-05 | 2022-08-05 |
| 10 MB | 5 MB | 3 MB | 50 MB |
| 50 | 40 | 30 | 100 |
Expected Result:
-----------------------------------------------------------------------------------
| Date | Method 1 Size | Method 1 Count | Method 2 Size | Method 2 Count |
-----------------------------------------------------------------------------------
| 2022-08-04 | 10 MB | 50 | 5 MB | 40 |
| 2022-08-05 | 3 MB | 30 | 50 MB | 100 |
-----------------------------------------------------------------------------------
Since the data I'm pushing into @cols
, each of the cols array element contains a hash with date, size and count. And while printing them it shows in horizontal way instead of showing it in vertically.
Also, sometimes there wouldn't be Method 2 hash values. In that scenario I need to display content of Method 1 hash values in table alone. How to achieve it in dynamic way?
CodePudding user response:
You have an outer loop over the fields (the copy and pasted lines), and an inner loop over the flattened records.
But the desired output shows a loop over the dates wrapping a loop over the methods wrapping a loop over the fields.
(Click to enlarge to get a better view.)
{
printf "| %-*s | ", 20, "Date";
for my $method ( "Method 1", "Method 2" ) {
printf "%-*s | %-*s |",
20, "$method Size",
20, "$method Count",
}
printf "\n";
}
for my $date ( sort keys( %hash ) ) {
my $by_method = $hash{ $date };
printf "| %-*s | ", $date;
for my $method ( "Method 1", "Method 2" ) {
my $rec = $by_method->{ $method };
printf "%-*s | %-*s |",
20, $rec->{ size },
20, $rec->{ count };
}
printf "\n";
}
There's a lot of magic numbers in there.
my @methods = ( "Method 1", "Method 2" );
my $date_size = 20;
my @field_defs = (
{ name => "Size", size => 20 },
{ name => "Count", size => 20 },
);
{
printf "| %-*s | ", $date_size, "Date";
for my $method ( @methods ) {
for my $field_def ( @field_defs ) {
printf "%-*s |", $field_def->{ size }, $field_def->{ name };
}
}
printf "\n";
}
for my $date ( sort keys( %hash ) ) {
my $by_method = $hash{ $date };
printf "| %-*s | ", $date_size, $date;
for my $method ( @methods ) {
my $rec = $by_method->{ $method };
for my $field_def ( @field_defs ) {
printf "%-*s |", $field_def->{ size }, $rec->{ $field_def->{ name } };
}
}
printf "\n";
}
The next step might be to calculate the minimum sizes instead of using 20
.
CodePudding user response:
Added as a new answer, because i think both styles are worth. Like i said in my other answer. Do the transformation of data before-hand. Then create your table. Here is another way of data-transformation by flattening the inner-hash first.
#!/usr/bin/env perl
use strict;
use warnings;
use v5.32;
use Data::Printer;
use Text::Table;
use List::Util qw(uniqstr);
my %hash = (
'2022-08-04' => {
'Method 1' => {
'Count' => 50,
'Size' => '10 MB'
},
'Method 2' => {
'Count' => 40,
'Size' => '5 MB'
}
},
'2022-08-05' => {
'Method 1' => {
'Count' => 30,
'Size' => '3 MB'
},
'Method 2' => {
'Size' => '50 MB',
'Count' => '100'
}
}
);
# Transform %hash by flattening the inner hashes
my