If the names and activities are variable, we can have a name that has a completely new activity that is not associated with any other name.
So in that case, the "activities" array should be built by looping through all names and their corresponding activities in the entire hash-of-hash data structure. That is, the following line in my earlier post:
14 my @activities = sort keys %{$result->{$names[0]}};
should change.
I have also changed the following two lines.
15 my $hdr_fmt = "%10s|%-6s|%-6s|%-6s|%-6s|\n";
16 my $row_fmt = "%-10s|%6d|%6d|%6d|%6d|\n";
The header and row format strings are now put inside a function that builds these strings dynamically, depending on the "names" array.
The modified code is below. The modifications are in red color.
$
$ cat -n print_hoh.pl
1 #!/usr/bin/perl -w
2 use strict;
3 my ($result, $name, $activities, $value, $hdr_fmt, $row_fmt);
4
5 # Subroutine section
6 sub build_hoh {
7 ($name, $activities, $value) = @_;
8 $result->{$name}->{$activities} = $value;
9 }
10
11 sub build_fmt_strings {
12 my $aref = shift;
13 $hdr_fmt = "%10s|";
14 $row_fmt = "%-10s|";
15 foreach my $i (@{$aref}) {
16 $hdr_fmt .= "%-6s|";
17 $row_fmt .= "%6s|";
18 }
19 $hdr_fmt .= "\n";
20 $row_fmt .= "\n";
21 }
22
23 sub print_hoh {
24 my @values = ();
25 my @names = sort keys %{$result};
26 # Since the activities could vary across names, loop through
27 # all activities, collect them in all_activities hash and sort
28 my %all_activities;
29 foreach my $i (keys %{$result}) {
30 foreach my $j (keys %{$result->{$i}}) {
31 $all_activities{$j}++;
32 }
33 }
34 my @activities = sort keys %all_activities;
35 # Now build the format strings and start printing
36 build_fmt_strings(\@names);
37 printf($hdr_fmt, "", @names);
38 foreach my $act (@activities) {
39 foreach my $name (@names) {
40 push(@values, $result->{$name}->{$act} // "");
41 }
42 printf($row_fmt, $act, @values);
43 @values = ();
44 }
45 }
46
47 # Main section
48 build_hoh("robert", "running", 10);
49 build_hoh("robert", "eating", 20);
50 build_hoh("robert", "sleeping", 9);
51 build_hoh("robert", "drinking", 0);
52 build_hoh("robert", "work", 10);
53
54 build_hoh("tom", "running", 8);
55 build_hoh("tom", "eating", 5);
56 build_hoh("tom", "sleeping", 9);
57 build_hoh("tom", "drinking", 1);
58 build_hoh("tom", "work", 10);
59
60 build_hoh("cat", "running", 3);
61 build_hoh("cat", "eating", 3);
62 #build_hoh("cat", "sleeping", 8);
63 build_hoh("cat", "drinking", 2);
64 build_hoh("cat", "work", 9);
65
66 build_hoh("peter", "running", 3);
67 build_hoh("peter", "eating", 2);
68 build_hoh("peter", "sleeping", 10);
69 build_hoh("peter", "drinking", 0);
70 build_hoh("peter", "work", 10);
71
72 build_hoh("john", "hiking", 99);
73 build_hoh("john", "work", 88);
74
75 print_hoh;
76
$
$
$ perl print_hoh.pl
|cat |john |peter |robert|tom |
drinking | 2| | 0| 0| 1|
eating | 3| | 2| 20| 5|
hiking | | 99| | | |
running | 3| | 3| 10| 8|
sleeping | | | 10| 9| 9|
work | 9| 88| 10| 10| 10|
$
$
---------- Post updated at 10:41 PM ---------- Previous update was at 10:13 PM ----------
In my next program, I have moved the variable data in a separate file altogether. It's the data file in csv format.
The data file name is passed to the Perl program, which then reads the data from the data file and prints the table dynamically.
$
$ # The data file
$ cat hoh_data.txt
robert,running,10
robert,eating,20
robert,sleeping,9
robert,drinking,0
robert,work,10
tom,running,8
tom,eating,5
tom,sleeping,9
tom,drinking,1
tom,work,10
cat,running,3
cat,eating,3
cat,drinking,2
cat,work,9
peter,running,3
peter,eating,2
peter,sleeping,10
peter,drinking,0
peter,work,10
john,hiking,99
john,work,88
$
$ # The program file
$ cat -n print_hoh_1.pl
1 #!/usr/bin/perl -w
2 use strict;
3 my ($result, $name, $activities, $value, $hdr_fmt, $row_fmt);
4
5 # Subroutine section
6 sub build_hoh {
7 ($name, $activities, $value) = @_;
8 $result->{$name}->{$activities} = $value;
9 }
10
11 sub build_fmt_strings {
12 my $aref = shift;
13 $hdr_fmt = "%10s|";
14 $row_fmt = "%-10s|";
15 foreach my $i (@{$aref}) {
16 $hdr_fmt .= "%-6s|";
17 $row_fmt .= "%6s|";
18 }
19 $hdr_fmt .= "\n";
20 $row_fmt .= "\n";
21 }
22
23 sub print_hoh {
24 my @values = ();
25 my @names = sort keys %{$result};
26 # Since the activities could vary across names, loop through
27 # all activities, collect them in all_activities hash and sort
28 my %all_activities;
29 foreach my $i (keys %{$result}) {
30 foreach my $j (keys %{$result->{$i}}) {
31 $all_activities{$j}++;
32 }
33 }
34 my @activities = sort keys %all_activities;
35 # Now build the format strings and start printing
36 build_fmt_strings(\@names);
37 printf($hdr_fmt, "", @names);
38 foreach my $act (@activities) {
39 foreach my $name (@names) {
40 push(@values, $result->{$name}->{$act} // "");
41 }
42 printf($row_fmt, $act, @values);
43 @values = ();
44 }
45 }
46
47 # Main section
48 # We read the hash-of-hash data from a file and build our data structure
49 my $file = $ARGV[0];
50 open(FH, "<", $file) or die "Can't open $file: $!";
51 while (<FH>) {
52 chomp(my $line = $_);
53 build_hoh(split(/,/, $line));
54 }
55 close(FH) or die "Can't close $file: $!";
56 print_hoh;
57
$
$
$ # Run the Perl program
$ perl print_hoh_1.pl hoh_data.txt
|cat |john |peter |robert|tom |
drinking | 2| | 0| 0| 1|
eating | 3| | 2| 20| 5|
hiking | | 99| | | |
running | 3| | 3| 10| 8|
sleeping | | | 10| 9| 9|
work | 9| 88| 10| 10| 10|
$
$
$ # Now add a new name and new activity and test
$
$ echo "wendy,yelling,55" >> hoh_data.txt
$
$ perl print_hoh_1.pl hoh_data.txt
|cat |john |peter |robert|tom |wendy |
drinking | 2| | 0| 0| 1| |
eating | 3| | 2| 20| 5| |
hiking | | 99| | | | |
running | 3| | 3| 10| 8| |
sleeping | | | 10| 9| 9| |
work | 9| 88| 10| 10| 10| |
yelling | | | | | | 55|
$
$
$ # Associate the new name with an existing activity and test
$
$ echo "wendy,running,66" >> hoh_data.txt
$
$ perl print_hoh_1.pl hoh_data.txt
|cat |john |peter |robert|tom |wendy |
drinking | 2| | 0| 0| 1| |
eating | 3| | 2| 20| 5| |
hiking | | 99| | | | |
running | 3| | 3| 10| 8| 66|
sleeping | | | 10| 9| 9| |
work | 9| 88| 10| 10| 10| |
yelling | | | | | | 55|
$
$