# Re: calculate within a loop

```
```
""Chris Charley"" <char...@pulsenet.com> wrote in message news:20160912202839.22177.qm...@lists-nntp.develooper.com...

```
```
"Nathalie Conte" <nco...@ebi.ac.uk> wrote in message news:9d0654e0-8ec0-4051-87ca-541f90931...@ebi.ac.uk...
```Dear all,

```
Thanks a lot for the codes various people which all work perfectly!! I have also discover some useful functions (eval and state) which can also be very helpful for this kind of data.
```
```
In the light of this, my dataset got more complicated, now there are 3 layers of hashes and I need now to calculate across those hashes for each name, I have tried to apply some of the code structure which were kindly provided and worked well for my first question, although as the data structure is now more complicated and I need to assess the data accross hashes makes it more complex and I din’t manage to get a solution for this. Again, any help would be greatly appreciated.
```##############
this is the dataset  now
\$VAR1 = {
'100 ' => {
'y' => {
'1' => 88,
'3' => 89,
'5' => 99
},
'x' => {
'1' => 97,
'3' => 117,
'5' => 107
},
'z' => {
'1' => 95,
'3' => 97,
'5' => 94
}
},
'101 ' => {
'y' => {
'1' => 188,
'3' => 189,
'5' => 199
},
'x' => {
'1' => 197,
'3' => 1117,
'5' => 1107
},
'z' => {
'1' => 195,
'3' => 197,
'5' => 194
}
}
};

########################
```
For each \$name (100 and 101)- there are 3 levels, x, y and z -Times are 1,3,5 for all datasets, across x, y and z . What needs to be calculated now with this more complex structure, is for each name, a calculation across the 3 hashes, for the 3 times.
```
for 100:
first line : no action
```
second line : should reflect the difference between time 3 and time 1 across x,y and z (x3-x1)+(y3-y1)+(z3-z1)
```time :3 - 1 =2,
```
value: calculation: x (value 3(117)-value 1(97) + y (value 3 (89)) - value 1 (88)) + z (value 3 (97) - value 1 (95))
```total should be : 117-97 + 89-88 +97-95 =13
```
third line: should reflect difference between time 5 and time 3 AND time 5 and time 1
```time : 5-3, and 5-1
```
value: calculation: difference between time 5 and time 3 : x (-value5 (107) - value 3(117)) + y (value5 (99)- value 3 (89)) + z (value 5 (94) - value 3 (97) ) = -3 total difference between time 5 and time 1 : x (-value5 (107) - value 1(97)) + y (value5 (99)- value 1 (88)) + z (value 5 (94) - value 1 (95) ) = 20 total
```
#######################
my partial code,
#!/usr/local/bin/perl
use strict;
use warnings;
use feature 'state';

use Data::Dumper qw(Dumper);
my %hall;

\$hall{"100 "}{'x'}{1}   = 97;
\$hall{"100 "}{'x'}{3}    = 117;
\$hall{"100 "}{'x'}{5}    = 107;
\$hall{"100 "}{'y'}{1}   = 88;
\$hall{"100 "}{'y'}{3}  = 89;
\$hall{"100 "}{'y'}{5}  = 99;
\$hall{"100 "}{'z'}{1}  = 95;
\$hall{"100 "}{'z'}{3}  = 97;
\$hall{"100 "}{'z'}{5}  = 94;
\$hall{"101 "}{'x'}{1}   = 197;
\$hall{"101 "}{'x'}{3}    = 1117;
\$hall{"101 "}{'x'}{5}    = 1107;
\$hall{"101 "}{'y'}{1}   = 188;
\$hall{"101 "}{'y'}{3}  = 189;
\$hall{"101 "}{'y'}{5}  = 199;
\$hall{"101 "}{'z'}{1}  = 195;
\$hall{"101 "}{'z'}{3}  = 197;
\$hall{"101 "}{'z'}{5}  = 194;

print Dumper \%hall;
print "----------------\n";

foreach  my \$name ( sort keys %hall) {
print "name.\$name\n";
foreach  my \$subject (sort keys %{ \$hall{\$name} }) {
print "suject.\$subject\n";

foreach  my \$values  ( sort  keys %{ \$hall{\$name}{\$subject}}) {

print "grade is .\$grade\n"; # this is not working and gives a reference!
my \$times = \$hall{\$name}{\$subject}{\$values};
print "time is .\$times\n";

if (eval { \$lgrade and \$lname eq \$name }) {

```
```       }

}
}
}

many thanks again for any tips/help,
```
```
#!/usr/bin/perl
use strict;
use warnings;
use List::Util 'sum';
use List::MoreUtils 'uniq';

my %hall = (
'100 ' => {
'y' => {
'1' => 88,
'3' => 89,
'5' => 99
},
'x' => {
'1' => 97,
'3' => 117,
'5' => 107
},
'z' => {
'1' => 95,
'3' => 97,
'5' => 94
}
},
'101 ' => {
'y' => {
'1' => 188,
'3' => 189,
'5' => 199
},
'x' => {
'1' => 197,
'3' => 1117,
'5' => 1107
},
'z' => {
'1' => 195,
'3' => 197,
'5' => 194
}
}
);

for my \$name (sort keys %hall) {
my \$href = \$hall{\$name};
my @keys = uniq sort {\$a <=> \$b} map keys %\$_, values %\$href;

for my \$i (0 .. \$#keys) {
for my \$j (\$i+1 .. \$#keys) {
my \$sum = sum( map \$_->{\$keys[\$j]}, values %\$href) -
sum( map \$_->{\$keys[\$i]}, values %\$href);
printf "%s \$keys[\$j] minus \$keys[\$i] %s\n", \$name, \$sum;
}
}
}

It gave as output:

100  3 minus 1 23
100  5 minus 1 20
100  5 minus 3 -3
101  3 minus 1 923
101  5 minus 1 920
101  5 minus 3 –3

```
```
```
My reply to Nathalie overlooked the fact that I was calculating sums multiple
```times for the same sets.

To improve the program, a cache could be created to eliminate the
multiple calls to 'sum'. Running the 2 versions on a large data set,
(1000 odd numbers), gave execution times of 24 seconds for
the cached version and 415 seconds for the non-cached one.

for my \$name (sort {\$a <=> \$b} keys %hall) {
my \$href = \$hall{\$name};
my @odds = uniq sort {\$a <=> \$b} map keys %\$_, values %\$href;

my %cache;
for my \$i (0 .. \$#odds) {

\$cache{ \$odds[\$i] } ||=
sum( map \$_->{\$odds[\$i]} || 0, values %\$href);

for my \$j (\$i+1 .. \$#odds) {

\$cache{ \$odds[\$j] } ||=
sum( map \$_->{\$odds[\$j]} || 0, values %\$href);

my \$sum = \$cache{ \$odds[\$j] } - \$cache{ \$odds[\$i] };
#print "\$name \$odds[\$j] minus \$odds[\$i] \$sum\n";
}
}
}

--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org