Push operation not working while pushing array to a hash - perl

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.

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

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.

Perl reference not printing the expected value

This is my program but why not it is printing my array values instead.
use strict;
use warnings;
use Data::Dumper;
my (#arr1,#arr2) = ([1,1,1,2,3,4],[5,5,5,6,9,87]);
my #arr3 = [\#arr1,\#arr2];
foreach (#arr3){
foreach (#$_){
print $_;
}
}
Output:
ARRAY(0x556414c6b908)ARRAY(0x556414c6b7e8)
but why not it is printing my array values instead.
Because the values are array references. To print the inner values, use dereference:
print #{ $array_ref };
For complex structures (arrays of arrays), you can use Data::Dumper:
use Data::Dumper;
print Dumper($array_ref);
But it still wouldn't work. You can't assign to several arrays at once. The first array gets all the values, the remaining arrays stay empty.
Documented in perlsub:
Do not, however, be tempted to do this:
(#a, #b) = upcase(#list1, #list2);
Like the flattened incoming parameter list, the return list is also
flattened on return. So all you have managed to do here is stored
everything in #a and made #b empty.
First of all, you weren't assigning anything to #arr2. You used something like the following to try to assign to #arr2:
(#arr1, #arr2) = ...;
However, Perl has no way to know how many scalars to assign to #arr1 and how many to assign to #arr2, so it assigns them all to #arr1. Use two different assignments instead.
Secondly, [ ] creates an array and returns a reference to it, so
my #arr1 = [1,1,1,2,3,4];
assigns a single scalar (a reference) to #arr1. This is what you are printing. You want
my #arr1 = (1,1,1,2,3,4);
Same goes for #arr2 and #arr3.
Therefore, your code should be
use strict;
use warnings;
use feature qw( say );
my #arr1 = (1,1,1,2,3,4);
my #arr2 = (5,5,5,6,9,87);
my #arr3 = (\#arr1,\#arr2);
for (#arr3) {
say join ", ", #$_;
}
or
use strict;
use warnings;
use feature qw( say );
my #arr3 = ([1,1,1,2,3,4],[5,5,5,6,9,87]);
for (#arr3) {
say join ", ", #$_;
}

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'
};

Put an array into a hash of hashes, transforming it into a Hash itself

my %hash = #array;
transforms an array into a hash, but how can do the same with $hash{something}?
$hash{something} = { #array };
The {} around it creates a hashref.
When you write:
my %hash = #array;
What Perl sees is:
my %hash = ($array[0], $array[1], ... $array[$#array]);
So the #array is expanded into a list, and that list is assigned to the plural %hash. The list must have an even number of elements, or you will get a warning (assuming you are using use warnings; in your script, which you always should. use strict; as well).
Broken down even more, it is:
my %hash;
$hash{$array[0]} = $array[1];
$hash{$array[2]} = $array[3];
...
$hash{$array[$#array - 1]} = $array[$#array];
So with the translation from #array to %hash explained, to insert this hash into a hash of hashes at a particular key:
$HoH{key} = \%hash;
Where the \ character takes a reference to %hash. If %hash is not needed elsewhere you could constrain it with a block:
{
my %hash = #array;
$HoH{key} = \%hash;
}
Using a do {...} makes it a little shorter:
$HoH{key} = do {my %hash = #array; \%hash};
But not much shorter. If the above seems tedious to you, it should. In Perl, the above construct can be reduced to:
$HoH{key} = { #array };
Where the {...} denotes the anonymous hash reference constructor, equivalent to
do {my %hash = (...); \%hash}
In addition to {...}, Perl provides the [...] construct to create anonymous array references. The ... of both constructs sees list context.