Reputation: 1112
below code works fine but if I replace push @array,{%hash}
with push @array,\%hash
then it doesn't. Can someone please help me understand the difference. I believe {%hash}
refers to an anonymous hash. Does it mean a anonymous hash lives longer than a reference to a named hash ( \%hash
).
use strict;
use warnings;
use Data::Dumper;
my @array;
my %hash;
%hash = ('a' => 1,
'b' => 2,
'c' => 3,);
push @array,{%hash};
%hash = ('e' => 1,
'f' => 2,
'd' => 3,);
push @array,{%hash};
print Dumper \@array;
output
$VAR1 = [
{
'c' => 3,
'a' => 1,
'b' => 2
},
{
'e' => 1,
'd' => 3,
'f' => 2
}
];
UPDATE Below is the actual code I am working on. I think in this case taking copy of the reference is the only possible solution I believe. Please correct me if I am wrong.
use Data::Dumper;
use strict;
use warnings;
my %csv_data;
my %temp_hash;
my @cols_of_interest = qw(dev_file test_file diff_file status);
<DATA>; #Skipping the header
while (my $row = <DATA>) {
chomp $row;
my @array = split /,/,$row;
@temp_hash{@cols_of_interest} = @array[3..$#array];
push @{$csv_data{$array[0]}{$array[1] . ':' . $array[2]}},{%temp_hash};
}
print Dumper \%csv_data;
__DATA__
dom,type,id,dev_file,test_file,diff_file,status
A,alpha,1234,dev_file_1234_1.txt,test_file_1234_1.txt,diff_file_1234_1.txt,pass
A,alpha,1234,dev_file_1234_2.txt,test_file_1234_2.txt,diff_file_1234_2.txt,fail
A,alpha,1234,dev_file_1234_3.txt,test_file_1234_3.txt,diff_file_1234_3.txt,pass
B,beta,4567,dev_file_4567_1.txt,test_file_4567_1.txt,diff_file_4567_1.txt,pass
B,beta,4567,dev_file_4567_2.txt,test_file_4567_2.txt,diff_file_4567_2.txt,fail
C,gamma,3435,dev_file_3435_1.txt,test_file_3435_1.txt,diff_file_3435_1.txt,pass
D,hexa,6768,dev_file_6768_1.txt,test_file_6768_1.txt,diff_file_6768_1.txt,fail
Upvotes: 3
Views: 278
Reputation: 386331
You can't really compare \
to {}
and []
since they don't do the same thing at all.
{ LIST }
is short for my %anon = LIST; \%anon
[ LIST ]
is short for my @anon = LIST; \@anon
Maybe you meant to compare
my %hash = ...;
push @a, \%hash;
push @a, { ... };
my %hash = ...;
push @a, { %hash };
The first snippet places a reference to %hash
in @a
. This is presumably found in a loop. As long as my %hash
is found in the loop, a reference to a new hash will be placed in @a
each time.
The second snippet does the same, just using an anonymous hash.
The third snippet makes a copy of %hash
, and places a reference to that copy in @a
. It gives the impression of wastefulness, so it's discouraged. (It's not actually not that wasteful because it allows %hash
to be reused.)
You could also write your code
# In reality, the two blocks below are probably the body of one sub or one loop.
{
my %hash = (
a => 1,
b => 2,
c => 3,
);
push @a, \%hash;
}
{
my %hash = (
d => 3,
e => 1,
f => 2,
);
push @a, \%hash;
}
or
push @a, {
a => 1,
b => 2,
c => 3,
};
push @a, {
d => 3,
e => 1,
f => 2,
};
my @cols_of_interest = qw( dev_file test_file diff_file status );
my %csv_data;
if (defined( my $row = <DATA> )) {
chomp $row;
my @cols = split(/,/, $row);
my %cols_of_interest = map { $_ => 1 } @cols_of_interest;
my @cols_to_delete = grep { !$cols_of_interest{$_} } @cols;
while ( my $row = <DATA> ) {
chomp $row;
my %row; @row{@cols} = split(/,/, $row);
delete @row{@cols_to_delete};
push @{ $csv_data{ $row{dev_file} }{ "$row{test_file}:$row{diff_file}" } }, \%row;
}
}
Better yet, let's use a proper CSV parser.
use Text::CSV_XS qw( );
my @cols_of_interest = qw( dev_file test_file diff_file status );
my $csv = Text::CSV_XS->new({
auto_diag => 2,
binary => 1,
});
my @cols = $csv->header(\*DATA);
my %cols_of_interest = map { $_ => 1 } @cols_of_interest;
my @cols_to_delete = grep { !$cols_of_interest{$_} } @cols;
my %csv_data;
while ( my $row = $csv->getline_hr(\*DATA) ) {
delete @$row{@cols_to_delete};
push @{ $csv_data{ $row->{dev_file} }{ "$row->{test_file}:$row->{diff_file}" } }, $row;
}
Upvotes: 3
Reputation: 54373
Both \%hash
and {%hash}
create references, but they reference two different things.
\%hash
is a ref to %hash
. If dereferenced, its values will change with the values in %hash
.
{%hash}
creates a new anonymous hash reference from the values in %hash
. It creates a copy. It's the simplest way of creating a shallow copy of a data structure in Perl. If you alter %hash
, this copy is not affected.
How long a variable lives has nothing to do with what kind the variable is, or how it was created. Only the scope is relevant for that. References in Perl are a special case here, because there is an internal ref counter that keeps track of references to a value, so that it is kept alive if there are still references around somewhere even if it goes out of scope. That's why this works:
sub frobnicate {
my %hash = ( foo => 'bar' );
return \%hash;
}
If you want to disassociate the reference from the initial value, you need to turn it into a weak reference via weaken
from Scalar::Util. That way, the ref count will not be influenced by it, but it will still be related to the value, while a copy would not be.
See perlref and perlreftut for more information on references. This question deals with how to see the ref count. A description for that is also available in the chapter Reference Counts and Mortality in perlguts.
Upvotes: 13