""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}}) {
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,
#!/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
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/