Search code examples
arraysperlhashhashmapperl-data-structures

Arithmetic operations between 2 hash arrays


I have a hash array with a YAML, which was taken from a linux command. I have another hash array, with the same YAML set, but with different values, by the same command, which was run at a later time.

Eg.

content.none: 
  bytes:  31046
content.image.gif: 
  bytes:  0

and

content.none: 
  bytes:  31050
content.image.gif: 
  bytes:  0

Now, I am looking for a math operation between the values. I am looking for an output

content.none: 
  bytes:  4
content.image.gif: 
  bytes:  0

which is the result of math between the corresponding values in the hash.

I tried iterating and doing diff, but it looks like a cumulative output.

%host_stat_new=New stats
 %host_stat_old=Old stats (taken from stats.yml, which contains old data)
while (true){
open my $FH1, ">stats.yml" or die "cannot write to stat file because $!\n";
foreach my $line4 (keys %host_stat_new){
        print $FH1 "$line4:\n";
        foreach my $line5 (keys %{$host_stat_new{$line4}}) {
                print $FH1 "  $line5: \n";
                foreach my $line6 (keys %{$host_stat_new{$line4}{$line5}}){
                my $diff1 = $host_stat_new{$line4}{$line5}{$line6};
                my $diff2 = $host_stat_old{$line4}{$line5}{$line6};


$math=$diff1-$diff2;
#$host_stat1{$line4}{$line5}{$line6} = $math;
$host_stat_new{$line4}{$line5}{$line6} = $math;
                    print $FH1 "    $line6:  $host_stat_new{$line4}{$line5}{$line6}\n";
                    }
            }


    }
}

What am I doing wrong here? Is there any module that can do this?


Solution

  • Just use some good ole recursion to get the diff. This function assumes that the data structures are identical, could add functionality to confirm that:

    use YAML;
    
    use strict;
    use warnings;
    
    my $str1 = <<YAML_STRING1;
    content.none: 
      bytes:  31046
    content.image.gif: 
      bytes:  0
    YAML_STRING1
    
    my $str2 = <<YAML_STRING2;
    content.none: 
      bytes:  31050
    content.image.gif: 
      bytes:  0
    YAML_STRING2
    
    my $data1 = Load($str1);
    my $data2 = Load($str2);
    
    my $diff = diff_recurse($data2, $data1);
    
    print Dump($diff);
    
    sub diff_recurse {
        my ($str1, $str2) = @_;
    
        my $diff;
    
        if ('HASH' eq ref $str1) {
            $diff = {};
            for my $key (keys %$str1) {
                $diff->{$key} = diff_recurse($str1->{$key}, $str2->{$key});
            }
    
        } elsif ('ARRAY' eq ref $str1) {
            $diff = [];
            for my $i (0..$#$str1) {
                $diff->[$i] = diff_recurse($str1->[$i], $str2->[$i]);
            }
    
        } elsif (my $unknown = ref $str1) {
            die "Unknown type $unknown\n";
    
        } elsif ($str1 =~ /^[\d\.]+$/) {
            $diff = $str1 - $str2;
        } else {
            $diff = $str1;
        }
    
        return $diff;
    }
    

    Outputs

    ---
    content.image.gif:
      bytes: 0
    content.none:
      bytes: 4