@Jim,

That eval bit i think Nathalie got from me. I need to review my core Perl. I 
think i’m in the habit of assuming Perl warns against any usage of undefined 
values, even in boolean context. Not so. I’ve proven to myself that this is not 
the case:

$ perl -E’
>my ($foo, $bar); # these aren’t defined
>if ($foo and $bar) {
>  say “doing something”;
>} else {
>  say “doing nothing”;
>}’
**output**
$ doing nothing

Good catch. Thanks Jim :)
> On Sep 12, 2016, at 1:22 PM, Chris Charley <char...@pulsenet.com> wrote:
> 
>  
> "Nathalie Conte" <nco...@ebi.ac.uk <mailto:nco...@ebi.ac.uk>> wrote in 
> message news:9d0654e0-8ec0-4051-87ca-541f90931...@ebi.ac.uk 
> <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}}) {
>         state ($lgrade,$lsubject,$lname,$ltimes);
>  
>        my $grade = $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 }) { 
>  
>             my ( $grade_diff, $times_diff) = ( $grade - $lgrade, 
> $times-$ltimes);
>             print "$name,  
> $grade-$lgrade=$grade_diff:$name,$times-$ltimes=$times_diff \n";
>         }
>  
>  
>  
>  
>         ($ltimes, $lgrade,$lname) = ($times, $grade,$name);
>     }
> }
> }
>  
> many thanks again for any tips/help,
>  
> I see Jim Gibson has solved this but I thought I’d add another solution.
>  
> Although it is a little more complex, it is shorter than Jim’s. It makes use 
> of 2 modules: List::Util=(sum) and List::MoreUtils=(uniq).
>  
> #!/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

Reply via email to