Sami_R has asked for the wisdom of the Perl Monks concerning the following question:
Morning Monks,
I have two hash and trying to join into one hash
#!/usr/bin/perl -w
use strict;
use warnings;
my $VAR1 = {
'Total' => {
'month1' => 0,
'month2' => 0,
'month3' => 0,
'month4' => 0,
'month5' => 0,
'month6' => 0,
'month7' => 0,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0,
'month16' => 0
},
'Tom' => {
'month1' => 17,
'month2' => 1,
'month3' => 15,
'month4' => 0,
'month5' => 3,
'month6' => 30,
'month7' => 33,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month12' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0
}
};
my $VAR2 = [
{
'Total' => {
'week1' => 0,
'week2' => 0,
'week3' => 0
},
'Harry' => {
'week1' => 0,
'week2' => 5,
'week3' => 5
}
}
];
my %joined_FS;
$joined_FS{$_} ||= {( %{$VAR1->{$_}||{}}, %{$VAR2->{$_}||{}} )} fo
+r keys(%$VAR1), keys(%$VAR2);
#This example was given by PerlMonks
print Dumper(\%joined_FS);
#Error:
Not a HASH reference at perl_script_work2.pl line 2441.
# Looks like your test exited with 255 just after 2.
Expected Output:
$VAR1 = {
'Tom' => {
'month1' => 17,
'month2' => 1,
'month3' => 15,
'month4' => 0,
'month5' => 3,
'month6' => 30,
'month7' => 33,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month12' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0
},
'Total' => {
'month1' => 0,
'month2' => 0,
'month3' => 0,
'month4' => 0,
'month5' => 0,
'month6' => 0,
'month7' => 0,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0,
'month16' => 0,
'week1' => 0,
'week2' => 0,
'week3' => 0
},
'Harry' => {
'week1' => 0,
'week2' => 5,
'week3' => 5
}
};
Please give me directions to fix this, many thanks.
Re: Error: when joining two hashes
by Laurent_R (Canon) on Feb 19, 2020 at 10:33 UTC
|
my $VAR2 = [ ...
is defined as an array ref, not a hash ref. | [reply] [d/l] |
|
$joined_FS{$_} ||= {( %{$VAR1->{$_}||{}}, @{$VAR2->{@_}||{}} )} for ke
+ys(%$VAR1), keys(@$VAR2);
I get same error ...
Is it possible to join array ref and hash ref please?
| [reply] [d/l] |
|
| [reply] |
|
|
|
|
I agree with Fletch that it seems a bit odd that your two variables don't have the same data structure. $VAR1 is a hash ref (or more precisely a reference to a hash of hashes), but $VAR2 is an array ref (a reference to an array of hashes of hashes), but there is no obvious reason in the data that you show to have an array as the top data structure. Is this data structure generated by your program at some earlier point? The proper fix would probably be to correct the part of the program that generates $VAR2, but you don't show that part.
| [reply] [d/l] [select] |
Re: Error: when joining two hashes
by haukex (Archbishop) on Feb 19, 2020 at 11:31 UTC
|
I'm making some assumptions about how you want the data merged, but at least the following produces your expected output:
use Hash::Merge;
my $merger = Hash::Merge->new();
my $joined_FS = {};
$joined_FS = $merger->merge($joined_FS, $_) for $VAR1, @$VAR2;
| [reply] [d/l] |
|
| [reply] |
Re: Error: when joining two hashes
by kcott (Archbishop) on Feb 20, 2020 at 08:28 UTC
|
$ perl -e '
use strict;
use warnings;
use Data::Dumper;
my $VAR1 = {
Total => { month1 => 0, month2 => 0 },
Tom => { month1 => 17, month2 => 1 },
};
my $VAR2 = [
{
Total => { week1 => 0, week2 => 0 },
Harry => { week1 => 0, week2 => 5 },
}
];
my %joined_FS = (
Total => {
%{delete $VAR1->{Total}},
%{delete $VAR2->[0]{Total}},
},
%$VAR1,
%{$VAR2->[0]}
);
print Dumper(\%joined_FS);
'
$VAR1 = {
'Tom' => {
'month1' => 17,
'month2' => 1
},
'Total' => {
'month2' => 0,
'month1' => 0,
'week2' => 0,
'week1' => 0
},
'Harry' => {
'week2' => 5,
'week1' => 0
}
};
| [reply] [d/l] |
|
| [reply] |
Re: Error: when joining two hashes
by BillKSmith (Monsignor) on Feb 19, 2020 at 16:09 UTC
|
Your code would work as expected if $VAR2 were a reference to a single hash rather than a reference to an array with one element (a hash ref).
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
my $VAR1 = {
'Total' => {
'month1' => 0,
'month2' => 0,
'month3' => 0,
'month4' => 0,
'month5' => 0,
'month6' => 0,
'month7' => 0,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0,
'month16' => 0
},
'Tom' => {
'month1' => 17,
'month2' => 1,
'month3' => 15,
'month4' => 0,
'month5' => 3,
'month6' => 30,
'month7' => 33,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month12' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0
}
};
my $VAR2 =
{
'Total' => {
'week1' => 0,
'week2' => 0,
'week3' => 0
},
'Harry' => {
'week1' => 0,
'week2' => 5,
'week3' => 5
}
};
my %joined_FS;
$joined_FS{$_} ||= {( %{$VAR1->{$_}||{}}, %{$VAR2->{$_}||{}} )} fo
+r keys(%$VAR1), keys(%$VAR2);
#This example was given by PerlMonks
print Dumper(\%joined_FS);
OUTPUT:
$VAR1 = {
'Tom' => {
'month10' => 0,
'month11' => 0,
'month15' => 0,
'month6' => 30,
'month7' => 33,
'month5' => 3,
'month13' => 0,
'month12' => 0,
'month4' => 0,
'month9' => 0,
'month3' => 15,
'month1' => 17,
'month2' => 1,
'month8' => 0,
'month14' => 0
},
'Total' => {
'week3' => 0,
'month6' => 0,
'week1' => 0,
'month10' => 0,
'month8' => 0,
'month2' => 0,
'month4' => 0,
'month5' => 0,
'month7' => 0,
'month15' => 0,
'month11' => 0,
'month14' => 0,
'month16' => 0,
'month1' => 0,
'month3' => 0,
'month9' => 0,
'month13' => 0,
'week2' => 0
},
'Harry' => {
'week3' => 5,
'week1' => 0,
'week2' => 5
}
};
| [reply] [d/l] |
|
my %joined_FS;
my %outer_keys;
for my $var (($VAR1, $VAR2))
{
if (ref $var eq "HASH")
{
while (my($key, $value) = each %$VAR1)
{
$outer_keys{$key} = $value;
}
}
elsif (ref $var eq "ARRAY")
{
for my $href (@$var)
{
my @unq_keys = keys %$href;
for my $key (@unq_keys)
{
if (!exists $outer_keys{$key})
{
$outer_keys{$key} = $href->{$key};
}
else
{
while (my($k, $v) = each %{$href->{$key}})
{
$outer_keys{$key}->{$k} = $v;
}
}
}
}
}
}
print Dumper \%outer_keys;
| [reply] [d/l] |
|
I showed that the original code would correctly merge two hashes. You have probably described Sami_R's problem correctly. In that case, all that is needed is another layer of indexing to correctly reference the second hash ($VAR2->[0] instead of $VAR2).
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests=>1;
my $VAR1 = {
'Total' => {
'month1' => 0,
'month2' => 0,
'month3' => 0,
'month4' => 0,
'month5' => 0,
'month6' => 0,
'month7' => 0,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0,
'month16' => 0
},
'Tom' => {
'month1' => 17,
'month2' => 1,
'month3' => 15,
'month4' => 0,
'month5' => 3,
'month6' => 30,
'month7' => 33,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month12' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0
}
};
my $VAR2 = [
{
'Total' => {
'week1' => 0,
'week2' => 0,
'week3' => 0
},
'Harry' => {
'week1' => 0,
'week2' => 5,
'week3' => 5
}
}
];
my $EXPECTED = {
'Tom' => {
'month1' => 17,
'month2' => 1,
'month3' => 15,
'month4' => 0,
'month5' => 3,
'month6' => 30,
'month7' => 33,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month12' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0
},
'Total' => {
'month1' => 0,
'month2' => 0,
'month3' => 0,
'month4' => 0,
'month5' => 0,
'month6' => 0,
'month7' => 0,
'month8' => 0,
'month9' => 0,
'month10' => 0,
'month11' => 0,
'month13' => 0,
'month14' => 0,
'month15' => 0,
'month16' => 0,
'week1' => 0,
'week2' => 0,
'week3' => 0
},
'Harry' => {
'week1' => 0,
'week2' => 5,
'week3' => 5
}
};
my %joined_FS;
$joined_FS{$_}
||= {
( %{$VAR1->{$_}||{}}, %{$VAR2->[0]->{$_}||{}} )
} for keys(%$VAR1), keys(%{$VAR2->[0]});
is_deeply(\%joined_FS, $EXPECTED, 'merge');
OUTPUT:
1..1
ok 1 - merge
| [reply] [d/l] [select] |
|
|