 Keep It Simple, Stupid PerlMonks

### Re^3: Refer calculated fields

by roboticus (Chancellor)
 on Feb 11, 2020 at 19:41 UTC Need Help??

in reply to Re^2: Refer calculated fields

I'm still a bit fuzzy on what you're asking. From your question title, it seems like you want to defer some calculations to a later time. While that's possible, the rest of your code implies that you're new to Perl.

So let's see if something simple will do what you want, first. Here's a bit of code that will keep a running sum of the input values. This lets you track the totals, but doesn't defer any calculations:

```use strict;
use warnings;

# Place to accumulate the values
my %sum;

my \$EquipName = "Switch";
my \$slot = "1";
my \$port = "FF";

while (my \$INPUT_LINE = <DATA>) {
chomp \$INPUT_LINE;

my \$KEY = \$EquipName . "." . \$slot . "." . \$port;

# Fetch out the values for the current line
my (\$PvcCount, \$LCir, \$RCir) = split /\s+/, \$INPUT_LINE;

# Add the values to the accumulators
\$sum{PvcCount}{\$KEY} += \$PvcCount;
\$sum{LCir}{\$KEY}     += \$LCir;
\$sum{RCir}{\$KEY}     += \$RCir;

# Print the current values
print "Line \$.: (PvcCount, LCir, RCir)  "
.     "CUR:(\$PvcCount, \$LCir, \$RCir)    "
.     "TTL:(\$sum{PvcCount}{\$KEY}, \$sum{LCir}{\$KEY}, \$sum{RCir}{\$KE
+Y})\n";
}

__DATA__
1   2   3
2   4   9
3   8  27
4  16  81

This should give you the following results:

```\$ perl pm_11112793.pl
Line 1: (PvcCount, LCir, RCir)  CUR:(1, 2, 3)    TTL:(1, 2, 3)
Line 2: (PvcCount, LCir, RCir)  CUR:(2, 4, 9)    TTL:(3, 6, 12)
Line 3: (PvcCount, LCir, RCir)  CUR:(3, 8, 27)    TTL:(6, 14, 39)
Line 4: (PvcCount, LCir, RCir)  CUR:(4, 16, 81)    TTL:(10, 30, 120)

As you see, we created a hash called %sum to hold the totals as we read them in. So while processing a line, we have access to the total so far but aren't able to know the final total until the final line. If we wanted the output to be like this:

```Line 1: (PvcCount, LCir, RCir)  CUR:(1, 2, 3)    TTL:(10, 30, 120)
Line 2: (PvcCount, LCir, RCir)  CUR:(2, 4, 9)    TTL:(10, 30, 120)
Line 3: (PvcCount, LCir, RCir)  CUR:(3, 8, 27)    TTL:(10, 30, 120)
Line 4: (PvcCount, LCir, RCir)  CUR:(4, 16, 81)    TTL:(10, 30, 120)

Then we'd have to read all the data before generating the output, because once we print a line, we can no longer change the values.

Some formats let you put things into the file in any order you like, such as PDF. If you were writing a PDF file, you could simply "remember" the locations to write the final values, and then when you hit the last line and can compute your totals, you could then write the totals in the remembered locations. For a Spreadsheet, you could provide a formula for computing the values and let the spreadsheet do the work when the spreadsheet user opens the sheet.

For a text file, though, you'd usually just parse the information and store it in a convenient format, and then after you're done reading the data, you'd then generate the report, something like this:

```use strict;
use warnings;

# Place to accumulate the values
my %sum;

# Place to store data before we print it.  When the KEY field changes,
+ we can then
# print all this data to the output
my @data;
my \$previous_KEY="";

while (my \$INPUT_LINE = <DATA>) {
chomp \$INPUT_LINE;

# Fetch out the values for the current line
my (\$EquipName, \$slot, \$port, \$PvcCount, \$LCir, \$RCir)
= split /\s+/, \$INPUT_LINE;

# Create the key to add the data to the proper thing
my \$KEY = \$EquipName . "." . \$slot . "." . \$port;

# If KEY doesn't match the old KEY, print the data then delete
# the data we no longer need.
if (\$previous_KEY ne \$KEY) {
print_data();

# then discard the (now unneeded) data and totals
@data = ();
%sum = ();
\$previous_KEY = \$KEY;
}

# Add the values to the accumulators
\$sum{PvcCount} += \$PvcCount;
\$sum{LCir}     += \$LCir;
\$sum{RCir}     += \$RCir;

# Store the data so we can print it later
push @data, [ \$., \$PvcCount, \$LCir, \$RCir ];
}

# Print data that may still be in @data and %sums
print_data();

# We made a subroutine to print the data because we need to
# call it from different places.  Inside the loop, we need to
# print the data when the key changes.  But we also need to
# call this it the end because there will probably still be
# some data in @data and %sum.
sub print_data {
my \$KEY = shift;
for my \$row (@data) {
print "Line \$row->: (PrvCount, LCir, RCir)  "
.     "CUR:(\$row->, \$row->, \$row->)    "
.     "TTL:(\$sum{PvcCount}, \$sum{LCir}, \$sum{RCir})\n";
}

}

__DATA__
Switch 1 FF 1   2   3
Switch 1 FF 2   4   9
Switch 1 FF 3   8  27
Switch 1 FF 4  16  81
Router 5 DA 8   5   1
Router 5 DA 9   6   3
Router 5 DA 7   1   9

\$ perl pm_11112793.pl
Line 1: (PrvCount, LCir, RCir)  CUR:(1, 2, 3)    TTL:(10, 30, 120)
Line 2: (PrvCount, LCir, RCir)  CUR:(2, 4, 9)    TTL:(10, 30, 120)
Line 3: (PrvCount, LCir, RCir)  CUR:(3, 8, 27)    TTL:(10, 30, 120)
Line 4: (PrvCount, LCir, RCir)  CUR:(4, 16, 81)    TTL:(10, 30, 120)
Line 5: (PrvCount, LCir, RCir)  CUR:(8, 5, 1)    TTL:(24, 12, 13)
Line 6: (PrvCount, LCir, RCir)  CUR:(9, 6, 3)    TTL:(24, 12, 13)
Line 7: (PrvCount, LCir, RCir)  CUR:(7, 1, 9)    TTL:(24, 12, 13)

As you can see, there's more work involved it you want to "go back in time" and print the final totals on earlier lines. It's also not normally needed. Usually in reports we'll just print the totals *after* all the details, which you can do with code more like the first example.

...roboticus

When your only tool is a hammer, all problems look like your thumb.

Create A New User
Node Status?
node history
Node Type: note [id://11112800]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (2)
As of 2020-10-25 21:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
My favourite web site is:

Results (249 votes). Check out past polls.

Notices?