Printing Hash in Perl - 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'
};

Related

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.

Perl Hash Value

Im trying to print perl hash value but its printing the ARRAY().
foreach my $key (sort keys %myHash) {
my $val = $myHash{$key};
print "$key => $val\n";
}
The Output is printing like
172 ARRAY(0x1c42548)
199 ARRAY(0x1c42638)
209 ARRAY(0x1c63360)
299 ARRAY(0x1c63390)
325 ARRAY(0x1c634e0)
Your values in your hash are themselves scalars pointing to arrays. Consider using Data::Dumper to print the value or if the elements of the arrays are scalars you can try something like the following.
The two builtin Perl collections, hashes and arrays, do not nest directly. They contain scalars which may be strings/numbers or references to hashes or arrays. There can also be references to functions and other more exotic things.
# Extract the array as an array and interpolate.
foreach my $key (sort keys %myHash) {
my #val = #{ $myHash{$key} };
print "$key => #val\n";
}
Data::Dumper exposes an option to sort keys.
# sample program using Data::Dumper
use strict;
use warnings;
use Data::Dumper;
local $Data::Dumper::Sortkeys = 1;
# obj is a reference to a hash.
my $obj = { 1 => 2, 3 => 4};
print Dumper($obj);
which prints
$VAR1 = {
'1' => 2,
'3' => 4
};

Reading a file content into perl hash using map

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.

Size of array inside hash

EDIT: Providing code as per demand from mppac:
I wanted the length of array inside hash.
Why is below showing undef?
$ >cat test.pl
#!/usr/bin/perl
use Data::Dumper;
my %static_data_key = (
'NAME' =>['RAM','SHYAM','RAVI','HARI'],
);
print Dumper(\%static_data_key);
$ >./test.pl
$VAR1 = {
'NAME' => [
'RAM',
'SHYAM',
'RAVI',
'HARI'
]
};
The return value of a Perl array in scalar context is the array's size. For example:
my #array = ( 'a', 'b', 'c' );
my $size = #array;
print "$size\n";
This code will print '3'. When dereferenced, anonymous arrays share this characteristic:
my $aref = [ 'a', 'b', 'c' ];
print $aref, "\n"; # ARRAY(0x1e33148)... useless in this case.
my $size = #{$aref}; # Dereference $aref, in scalar context.
print "$size\n"; # 3
The code I'm demonstrating takes a few unnecessary steps to lend clarity. Now consider this:
print scalar #{[ 'a', 'b', 'c']}, "\n"; # 3
Here we're constructing an anonymous array and immediately dereferencing it. We obtain its return value in scalar context, which happens to be 3.
Finally, let's put that anonymous array into a hash:
my %hash = (
NAME => [ 'joseph', 'frank', 'pete' ]
);
print scalar #{$hash{NAME}}, "\n";
Read that last line from the middle outward; first we obtain the value stored the NAME element within %hash. That is a reference to an anonymous array. So we dereference it with #{ ..... }. And we use scalar to force scalar context. The output is 3.
#!/usr/bin/perl
# your code goes here
use strict;
use warnings;
my %static_data_key = (
'NAME' =>['RAM','SHYAM','RAVI','HARI'],
);
print scalar #{$static_data_key{'NAME'}};
Demo

Build hash of hash in perl

I'm new to using perl and I'm trying to build a hash of a hash from a tsv. My current process is to read in a file and construct a hash and then insert it into another hash.
my %hoh = ();
while (my $line = <$tsv>)
{
chomp $line;
my %hash;
my #data = split "\t", $line;
my $id;
my $iter = each_array(#columns, #data);
while(my($k, $v) = $iter->())
{
$hash{$k} = $v;
if($k eq 'Id')
{
$id = $v;
}
}
$hoh{$id} = %hash;
}
print "dump: ", Dumper(%hoh);
This outputs:
dump
$VAR1 = '1234567890';
$VAR2 = '17/32';
$VAR3 = '1234567891';
$VAR4 = '17/32';
.....
Instead of what I would expect:
dump
{
'1234567890' => {
'k1' => 'v1',
'k2' => 'v2',
'k3' => 'v3',
'k4' => 'v4',
'id' => '1234567890'
},
'1234567891' => {
'k1' => 'v1',
'k2' => 'v2',
'k3' => 'v3',
'k4' => 'v4',
'id' => '1234567891'
},
........
};
My limited understanding is that when I do $hoh{$id} = %hash; its inserting in a reference to %hash? What am I doing wrong? Also is there a more succint way to use my columns and data array's as key,value pairs into my %hash object?
-Thanks in advance,
Niru
To get a reference, you have to use \:
$hoh{$id} = \%hash;
%hash is the hash, not the reference to it. In scalar context, it returns the string X/Y wre X is the number of used buckets and Y the number of all the buckets in the hash (i.e. nothing useful).
To get a reference to a hash variable, you need to use \%hash (as choroba said).
A more succinct way to assign values to columns is to assign to a hash slice, like this:
my %hoh = ();
while (my $line = <$tsv>)
{
chomp $line;
my %hash;
#hash{#columns} = split "\t", $line;
$hoh{$hash{Id}} = \%hash;
}
print "dump: ", Dumper(\%hoh);
A hash slice (#hash{#columns}) means essentially the same thing as ($hash{$columns[0]}, $hash{$columns[1]}, $hash{$columns[2]}, ...) up to however many columns you have. By assigning to it, I'm assigning the first value from split to $hash{$columns[0]}, the second value to $hash{$columns[1]}, and so on. It does exactly the same thing as your while ... $iter loop, just without the explicit loop (and it doesn't extract the $id).
There's no need to compare each $k to 'Id' inside a loop; just store it in the hash as a normal field and extract it afterwards with $hash{Id}. (Aside: Is your column header Id or id? You use Id in your loop, but id in your expected output.)
If you don't want to keep the Id field in the individual entries, you could use delete (which removes the key from the hash and returns the value):
$hoh{delete $hash{Id}} = \%hash;
Take a look at the documentation included in Perl. The command perldoc is very helpful. You can also look at the Perldoc webpage too.
One of the tutorials is a tutorial on Perl references. It all help clarify a lot of your questions and explain about referencing and dereferencing.
I also recommend that you look at CPAN. This is an archive of various Perl modules that can do many various tasks. Look at Text::CSV. This module will do exactly what you want, and even though it says "CSV", it works with tab separated files too.
You missed putting a slash in front of your hash you're trying to make a reference. You have:
$hoh{$id} = %hash;
Probably want:
$hoh{$id} = \%hash;
also, when you do a Data::Dumper of a hash, you should do it on a reference to a hash. Internally, hashes and arrays have similar structures when a Data::Dumper dump is done.
You have:
print "dump: ", Dumper(%hoh);
You should have:
print "dump: ", Dumper( \%hoh );
My attempt at the program:
#! /usr/bin/env perl
#
use warnings;
use strict;
use autodie;
use feature qw(say);
use Data::Dumper;
use constant {
FILE => "test.txt",
};
open my $fh, "<", FILE;
#
# First line with headers
#
my $line = <$fh>;
chomp $line;
my #headers = split /\t/, $line;
my %hash_of_hashes;
#
# Rest of file
#
while ( my $line = <$fh> ) {
chomp $line;
my %line_hash;
my #values = split /\t/, $line;
for my $index ( ( 0..$#values ) ) {
$line_hash{ $headers[$index] } = $values[ $index ];
}
$hash_of_hashes{ $line_hash{id} } = \%line_hash;
}
say Dumper \%hash_of_hashes;
You should only store a reference to a variable if you do so in the last line before the variable goes go of scope. In your script, you declare %hash inside the while loop, so placing this statement as the last in the loop is safe:
$hoh{$id} = \%hash;
If it's not the last statement (or you're not sure it's safe), create an anonymous structure to hold the contents of the variable:
$hoh{$id} = { %hash };
This makes a copy of %hash, which is slower, but any subsequent changes to it will not effect what you stored.