Reading a file content into perl hash using map - perl

I am trying to read the contents of a file into a hash
file contents look line,
A|A1
B|B1
C|C1
the code I have is
use strict;
use warnings;
use Data::Dumper;
my $instAttribFileName="DATABYIDENTIFIER_InstCommonAttrList.config";
open(IFH,$instAttribFileName) or die "cannot open file";
my %attribhash = ();
%attribhash = map {chomp; split /\|/} (<IFH>);
print Dumper %attribhash;
Dumper does not print the hash but reads A,A1 etc into seperate variables.
what am I doing wrong here?

According to perldoc perldata:
LISTs do automatic interpolation of sublists. That is, when a LIST is
evaluated, each element of the list is evaluated in list context, and
the resulting list value is interpolated into LIST just as if each
individual element were a member of LIST. Thus arrays and hashes lose
their identity in a LIST
So you need to pass the hash by reference to Dumper() or else it will be flattened into a list of separate arguments. For example, if you have:
my %foo = ( a => 'A', b => 'B');
print Dumper %foo;
Output:
$VAR1 = 'b';
$VAR2 = 'B';
$VAR3 = 'a';
$VAR4 = 'A';
but if you pass a reference to %foo instead (by putting a backslash in front):
print Dumper \%foo;
we get:
$VAR1 = {
'b' => 'B',
'a' => 'A'
};
References:
Data::Dumper
perldoc perlref
How can I print the contents of a hash in Perl?

It's always worth reading all of the documentation for the modules you're trying to use. The "BUGS" section in the Data::Dumper manual says:
Due to limitations of Perl subroutine call semantics, you cannot pass an array or hash. Prepend it with a \ to pass its reference instead.

Related

How to take a hash from Perl array?

This is the code:
my #items = (); # this is the array
my %x = {}; # the hash I'm going to put into the array
$x{'aa'} = 'bb'; # fill it up with one key-value pair
push(#items, $x); # add it to the array
my %i = #items[0]; # taking it back
print $i{'aa'}; # taking the value by the key
I expect it to print bb, but it doesn't print anything. What am I doing wrong?
What am I doing wrong?
Well, this doesn't do what you think:
my %x = {};
You can easily check:
use Data::Dumper;
print Dumper \%x;
The output:
Reference found where even-sized list expected at ./1.pl line 5.
$VAR1 = {
'HASH(0x556a69fe8220)' => undef
};
The first line comes from use warnings;. If you don't use it, start now.
Why is the contents of the hash so strange? The curly braces create a hash reference. As keys must be strings, the reference is stringified to the HASH(0xADDR). You don't want a reference, you want a list of keys and values.
my %x = ();
In fact, each hash and array starts up empty, so you don't have to use anything:
my #items;
my %x;
Or, you can populate it right ahead instead of doing it separately on the next line:
my %x = (aa => 'bb');
Similarly, this doesn't work:
push #items, $x;
It pushes value of the scalar variable $x into #items, but there's no such variable. It seems you aren't using use strict;. Start now, it will save you from similar errors.
You want to push the hash to the array, but array values are scalars - so you need to take a reference of the hash instead.
push #items, \%x;
No, you want to retrieve the hash from the array. Again, this doesn't work:
my %i = #items[0];
You are extracting a single value. Therefore, you shouldn't use #. Moreover, we now have a reference in the array, to populate a hash, we need to dereference it first:
my %i = %{ $items[0] };
And voilĂ , it works!
#!/usr/bin/perl
use warnings;
use strict;
my #items; # this is the array
my %x; # the hash I'm going to put into the array
$x{aa} = 'bb'; # fill it up with one key-value pair
push #items, \%x; # add it to the array
my %i = %{ $items[0] }; # taking it back
print $i{aa}; # taking the value by the key

Push operation not working while pushing array to a hash

I have two arrays #arr1 and #arr2 and I have a hash %hash in my Perl code.
I have certain elements in #arr1 and similarly certain elements in #arr2. I want to push elements of #arr1 as key for hash %hash and elements of the array #arr2 as values for those keys for hash %hash.
I am using the below code in my Perl script to do so:
use strict;
use warnings;
use Data::Dumper;
my %hash = ();
my #abc = ('1234', '2345', '3456', '4567');
my #xyz = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
push(#{$hash{#abc}}, #xyz);
print Dumper(%hash);
After executing, I am getting the below output:
./test.pl
$VAR1 = '4';
$VAR2 = [
'1234.txt',
'2345.txt',
'3456.txt',
'4567.txt'
];
It is not printing the key values but their total number. I need the output to be that every key with its value gets printed after I execute the script.
Can someone please help. Thanks.
You're looking for a slice to assign multiple elements of a hash at once:
use strict;
use warnings;
use Data::Dumper;
my %hash = ();
my #abc = ('1234', '2345', '3456', '4567');
my #xyz = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
#hash{#abc} = #xyz;
print Dumper(\%hash);
produces (Though order of keys might vary):
$VAR1 = {
'4567' => '4567.txt',
'2345' => '2345.txt',
'3456' => '3456.txt',
'1234' => '1234.txt'
};
Explanation
What push(#{$hash{#abc}}, #xyz); does is push elements into an array reference stored in a single hash entry - #abc is used in scalar context here, which evaluates to the length of the array, hence the 4. Using a slice instead assigns a list of values to a corresponding list of keys.
Then print Dumper(%hash); first turns %hash into a list of alternating keys and values, hence them being two different Data::Dumper entries. Passing a reference to the hash instead makes it print out the actual data structure as one thing.

Why is my hash getting flattened?

I am passing an array of references by reference to a subroutine. When I try to deference it in a sub-routine, it gives a flattened hash. How can I fix this? I don't want to have a flat hash and I am unable determine the reason for this.
I am sure that I am making a mistake somewhere but not able to spot it. Any comments/suggestions are totally welcome! Looking forward to hear from this wonderful community! Thanks in advance.
updated problem statement:
Basically I am looking to pass a hash by reference to a sub-routine. And my issue is that when I accept it in the subroutine with a scalar variable, and then I try to de-reference it with % symbol, I still get a flat hash.
update: There was a confusion.As I was checking whether my hash is flat or not - I checked only with print Dumper %hash when I should actually have actually checked with print Dumper \%hash. Lack of this piece of information caused this issue.
Script:
#!/usr/bin/perl
use strict ;
use warnings ;
use Data::Dumper ;
my %h = (moe => "joe", toe => "poe") ;
my #a = (1,2,3,4) ;
my #refs = \(%h,#a) ;
sub sample()
{
my $ref = shift ;
my #refs = #{$ref} ;
print "What I got in the sub! Seems OK!!\n" ;
print Dumper #refs, "\n" ;
my %h = %{$refs[0]} ;
my #a = #{$refs[1]} ;
print "I am not able to dereference this :(. Please help!! Hash is flat :(\n" ;
print Dumper %h ;
print Dumper #a ;
}
&sample(\#refs) ;
OUTPUT:
23:34:17[Host#User]$ ./test.pl
What I got in the sub! Seems OK!!
$VAR1 = {
'moe' => 'joe',
'toe' => 'poe'
};
$VAR2 = [
1,
2,
3,
4
];
$VAR3 = '
';
I am not able to dereference this :(. Please help!! Hash is flat :(
$VAR1 = 'moe';
$VAR2 = 'joe';
$VAR3 = 'toe';
$VAR4 = 'poe';
$VAR1 = 1;
$VAR2 = 2;
$VAR3 = 3;
$VAR4 = 4;
There's nothing to fix. You have what you wanted. You have a hash in %h and an array in #a.
But Data::Dumper takes a list of arguments and it treats each of its arguments as a separate variable to dump. So when you pass either a hash or an array to Dumper(), they will be unrolled into a list and you'll get them displayed as separate variables.
If you want to see the structure of an array or a hash using Dumper(), you should pass in a reference to the data structure instead.
print Dumper \%h;
print Dumper \#a;
Of course, that's effectively what you're doing on your first call to Dumper().
print Dumper #refs;
I should also point out that you have a couple of errors in your code that (fortunately?) cancel each other out. You define your subroutine sample with an empty prototype (sample() { ... }) which means that you will get a fatal error if you pass it any arguments. But when you call the subroutine, you use an & (&sample(#refs)) and one of the effects of that is to turn off prototype checking - so it works even though you pass arguments to the subroutine.
Best to omit the prototype completely (sub sample { ... }) and call the subroutine without the ampersand (sample(#refs))).

Printing Hash in Perl

I want to know the following code why print "2/8".
#!/usr/bin/perl
#use strict;
#use warnings;
%a = ('a'=>'dfsd','b'=>'fdsfds');
print %a."\n";
You are printing a hash in scalar context by concatenating it with a string '\n'
If you evaluate a hash in scalar context, it returns false if the hash
is empty. If there are any key/value pairs, it returns true; more
precisely, the value returned is a string consisting of the number of
used buckets and the number of allocated buckets, separated by a
slash.
2/8 means that of the 8 buckets allocated, 2 have been touched. Considering that you've inserted only 2 values, it is doing well so far :)
The value is obviously of no use, except to evaluate how well the hash-function is doing. Use print %a; to print its contents.
As mentioned by #Dark.. you are printing a hash in scalar context.
if you really want to print a hash, then use Data::Dumper
use Data::Dumper;
...
...
print Dumper(%a);
for eg:
use Data::Dumper;
my %hash = ( key1 => 'value1', key2 => 'value2' );
print Dumper(%hash); # okay, but not great
print "or\n";
print Dumper(\%hash); # much better
And the output:
$VAR1 = 'key2';
$VAR2 = 'value2';
$VAR3 = 'key1';
$VAR4 = 'value1';
or
$VAR1 = {
'key2' => 'value2',
'key1' => 'value1'
};

Dereferencing a list reference in hash element

Can someone finish this for me and explain what you did?
my %hash;
#$hash{list_ref}=[1,2,3];
#my #array=#{$hash{list_ref}};
$hash{list_ref}=\[1,2,3];
my #array=???
print "Two is $array[1]";
#array = #{${$hash{list_ref}}};
(1,2,3) is a list.
[1,2,3] is a reference to a list an array (technically, there's no such thing in Perl as a reference to a list).
\[1,2,3] is a reference to a reference to an array.
$hash{list_ref} is a reference to a reference to an array.
${$hash{list_ref}} is a reference to an array.
#{${$hash{list_ref}}} is an array.
Since a reference is considered a scalar, a reference to a reference is a scalar reference, and the scalar dereferencing operator ${...} is used in the middle step.
Others have pretty much already answered the question, but more generally, if you are ever confused about a data structure, use Data::Dumper. This will print out the structure of the mysterious blob of data, and help you parse it.
use strict; #Always, always, always
use warnings; #Always, always, always
use feature qw(say); #Nicer than 'print'
use Data::Dumper; #Calling in the big guns!
my $data_something = \[1,2,3];
say Dumper $data_something;
say Dumper ${ $data_something };
Let's see what it prints out...
$ test.pl
$VAR1 = \[
1,
2,
3
];
$VAR1 = [
1,
2,
3
];
From the first dump, it appears that $data_something is a plain scalar reference to an array reference. That lead me to add the second Dumper after I ran the program the first time. That showed me that ${ $data_something } is now a reference to an array.
I can now access that array like this:
use strict; #Always, always, always
use warnings; #Always, always, always
use feature qw(say); #Nicer than 'print'
use Data::Dumper; #Calling in the big guns!
my $data_something = \[1,2,3];
# Double dereference
my #array = #{ ${ $data_something } }; #Could be written as #$$data_something
for my $element (#array) {
say "Element is $element";
}
And now...
$ test.pl
Element is 1
Element is 2
Element is 3
It looks like you meant:
my $hash{list_ref} = [1,2,3];
and not:
$hash{list_ref} = \[1,2,3];
That latter one got you an scalar reference of a array reference which really doesn't do you all that much good except add confusion to the situation.
Then, all you had to do to refer to a particular element is $hash{list_ref}->[0]. This is just a shortcut for ${ $hash{list_ref} }[0]. It's easier to read and understand.
use strict;
use warnings;
use feature qw(say);
my %hash;
$hash{list_ref} = [1, 2, 3];
foreach my $element (0..2) {
say "Element is " . $hash{list_ref}->[$element];
}
And...
$ test.pl
Element is 1
Element is 2
Element is 3
So, next time you are confused about what a particular data structure looks like (and it happens to the best of us. Well... not the best of us, It happens to me), use Data::Dumper.
my %hash;
#$hash{list_ref}=[1,2,3];
#Putting the list in square brackets makes it a reference so you don't need '\'
$hash{list_ref}=[1,2,3];
#If you want to use a '\' to make a reference it is done like this:
# $something = \(1,2,3); # A reference to a list
#
# or (as I did above)...
#
# $something = [1,2,3]; # Returns a list reference
#
# They are the same (for all intent and purpose)
print "Two is $hash{list_ref}->[1]\n";
# To make it completely referenced do this:
#
# $hash = {};
# $hash->{list_ref} = [1,2,3];
#
# print $hash->{list_ref}[1] . "\n";
To get at the array (as an array or list) do this:
my #array = #{ $hash{list_ref} }
[ EXPR ]
creates an anonymous array, assigns the value returned by EXPR to it, and returns a reference to it. That means it's virtually the same as
do { my #anon = ( EXPR ); \#anon }
That means that
\[ EXPR ]
is virtually the same as
do { my #anon = ( EXPR ); \\#anon }
It's not something one normally sees.
Put differently,
1,2,3 returns a list of three elements (in list context).
(1,2,3) same as previous. Parens simply affect precedence.
[1,2,3] returns a reference to an array containing three elements.
\[1,2,3] returns a reference to a reference to an array containing three elements.
In practice:
my #data = (1,2,3);
print #data;
my $data = [1,2,3]; $hash{list_ref} = [1,2,3];
print #{ $data }; print #{ $hash{list_ref} };
my $data = \[1,2,3]; $hash{list_ref} = \[1,2,3];
print #{ ${ $data } }; print #{ ${ $hash{list_ref} } };