Iterate through hash values in perl - perl

I've got a hash with let's say 20 values.
It's initialized this way:
my $line = $_[0]->[0];
foreach my $value ($line) {
print $value;
}
Now when I try to get the value of each hash in $line it says:
Use of uninitialized value in print at file.pl line 89
Is there a way to iterate through each value of a hash?
I also tried it with:
my %line = $_[0]->[0];
foreach my $key (keys %line) {
print %line->{$key};
}
But that is also not working:
Reference found where even-sized list expected at file.pl at line 89
Anybody knows what to do? It shouldn't be that difficult...

To iterate over values in a hash:
for my $value (values %hash) {
print $value;
}

$line in your first example is a scalar, not a hash.
If it's a hash reference, dereference it with %{$line}.

First, you must understand the difference between a hash, and a hash reference.
Your initial assignment $_[0]->[0] means something like : Takes the first argument of the current function ($_[0]), dereference it (->) and consider it is an array and retrieves it's first value ([0]). That value can not be a list or a hash, it must be a scalar (string, int, float, reference).
Here is some example:
my %hash = ( MyKey => "MyValue");
my $hashref = \%hash;
# The next line print all elements of %hash
foreach (keys %hash) { print $_ }
# And is equivalent to
foreach (keys %{$hashref}) { print $_ }
$hash{MyKey} == $hashref->{MyKey}; # is true
Please refer to http://perldoc.perl.org/perlreftut.html for further details.

The warning is telling you that there nothing at $_[0]->[0]. It's not dying and telling you that you're indexing nothing, so $_[0] is likely an arrayref, but nothing is in the first slot--or perhaps it's pointing to an empty array.
Were it a empty string or a 0, it wouldn't complain.
Were there any reference there, you could print something even if only: BLAH(0x80af74). (Where "BLAH" is one of "ARRAY", "HASH", "SCALAR", "REF", "GLOB", "IO", ... )
My suggestion is that you do this:
use Data::Dumper;
say Data::Dumper->Dump( [ $_[0] ] ); # or even say Data::Dumper->Dump( [ \#_ ] )
and then look at the output.
Once you've got a hashref at $_[0]->[0], then if you must loop through the hash, the best way is:
while ( my ( $key, $value ) = each %$hashref ) {
do_stuff_with_key_and_value( $key, $value );
}
see each
Lastly, it seems that you have some sigil confusion. See the last part of this link for a decent attempt to explain that sigils ( '$', '#', '%' ) are not part of the name of a variable, but indicators what we want retrieved from it. Perl compilation woes

Related

How do I return an array and a hashref?

I want to make a subroutine that adds elements (keys with values) to a previously-defined hash. This subroutine is called in a loop, so the hash grows. I don’t want the returning hash to overwrite existing elements.
At the end, I would like to output the whole accumulated hash.
Right now it doesn’t print anything. The final hash looks empty, but that shouldn’t be.
I’ve tried it with hash references, but it does not really work. In a short form, my code looks as follows:
sub main{
my %hash;
%hash=("hello"=>1); # entry for testing
my $counter=0;
while($counter>5){
my(#var, $hash)=analyse($one, $two, \%hash);
print ref($hash);
# try to dereference the returning hash reference,
# but the error msg says: its not an reference ...
# in my file this is line 82
%hash=%{$hash};
$counter++;
}
# here trying to print the final hash
print "hash:", map { "$_ => $hash{$_}\n" } keys %hash;
}
sub analyse{
my $one=shift;
my $two=shift;
my %hash=%{shift #_};
my #array; # gets filled some where here and will be returned later
# adding elements to %hash here as in
$hash{"j"} = 2; #used for testing if it works
# test here whether the key already exists or
# otherwise add it to the hash
return (#array, \%hash);
}
but this doesn’t work at all: the subroutine analyse receives the hash, but its returned hash reference is empty or I don’t know. At the end nothing got printed.
First it said, it's not a reference, now it says:
Can't use an undefined value as a HASH reference
at C:/Users/workspace/Perl_projekt/Extractor.pm line 82.
Where is my mistake?
I am thankful for any advice.
Arrays get flattened in perl, so your hashref gets slurped into #var.
Try something like this:
my ($array_ref, $hash_ref) = analyze(...)
sub analyze {
...
return (\#array, \#hash);
}
If you pass the hash by reference (as you're doing), you needn't return it as a subroutine return value. Your manipulation of the hash in the subroutine will stick.
my %h = ( test0 => 0 );
foreach my $i ( 1..5 ) {
do_something($i, \%h);
}
print "$k = $v\n" while ( my ($k,$v) = each %h );
sub do_something {
my $num = shift;
my $hash = shift;
$hash->{"test${num}"} = $num; # note the use of the -> deference operator
}
Your use of the #array inside the subroutine will need a separate question :-)

Traversing Array of Hashes in perl

I have a structure as below:
my $var1 = [{a=>"B", c=>"D"}, {E=>"F", G=>"H"}];
Now I want to traverse the first hash and the elements in it.. How can I do it?
When I do a dumper of $var1 it gives me Array and when on #var1 it says a hash.
You iterate over the array as you would with any other array, and you'll get hash references. Then iterate over the keys of each hash as you would with a plain hash reference.
Something like:
foreach my $hash (#{$var1}) {
foreach my $key (keys %{$hash}) {
print $key, " -> ", $hash->{$key}, "\n";
}
}
First off, you're going to trip Perl's strict mode with your variable declaration that includes barewords.
With that in mind, complete annotated example given below.
use strict;
my $test = [{'a'=>'B','c'=>'D'},{'E'=>'F','G'=>'H'}];
# Note the #{ $test }
# This says "treat this scalar reference as a list".
foreach my $elem ( #{ $test } ){
# At this point $elem is a scalar reference to one of the anonymous
# hashes
#
# Same trick, except this time, we're asking Perl
# to treat the $elem reference as a reference to hash
#
# Hence, we can just call keys on it and iterate
foreach my $key ( keys %{ $elem } ){
# Finally, another bit of useful syntax for scalar references
# The "point to" syntax automatically does the %{ } around $elem
print "Key -> $key = Value " . $elem->{$key} . "\n";
}
}
C:\wamp\bin\perl\bin\PERL_2~1\BASIC_~1\REVISION>type traverse.pl
my $var1=[{a=>"B", c=>"D"},{E=>"F", G=>"H"}];
foreach my $var (#{$var1}) {
foreach my $key (keys(%$var)) {
print $key, "=>", $var->{$key}, "\n";
}
print "\n";
}
C:\wamp\bin\perl\bin\PERL_2~1\BASIC_~1\REVISION>traverse.pl
c=>D
a=>B
G=>H
E=>F
$var1 = [] is a reference to an anonymous array
using the # sigil before it as in $var1 gives you the access to the array it is referencing. So analogous to foreach (#arr) {...} you would do foreach (#{$var1}) {...}.
Now, the elements in the array that you have provided #{$var1} are anonymous (means not named) too, but they are anonymous hashes, so just like with the arrayref, here we do %{$hash_reference} to get access to the hash referenced by $hash_reference. Here, $hash_reference is $var.
After accessing the hash using %{$var} it becomes easy to access the keys of the hash using keys(%$var) or keys(%{$var}). Since the result returned is an array of keys therefore we can use keys(%{$var}) inside foreach (keys(%{$var})) {...}.
We access the scalar value inside an anonymous hash by using a key like $hash_reference->{$keyname}, that's all the code did.
In case your array contained anonymous hashes of arrays like :
$var1=[ { akey=>["b", "c"], mkey=>["n", "o"]} ];
then, this is how you will access the array values:
C:\wamp\bin\perl\bin\PERL_2012\BASIC_PERL\REVISION>type traverse.pl
my $var1=[ {akey=>["b", "c"], mkey=>["n", "o"]} ];
foreach my $var (#{$var1}) {
foreach my $key (keys(%$var)) {
foreach my $elem (#{ $var->{$key} }) {
print "$key=>$elem,";
}
print "\n...\n";
}
print "\n";
}
C:\wamp\bin\perl\bin\PERL_2012\BASIC_PERL\REVISION>traverse.pl
mkey=>n,mkey=>o,
...
akey=>b,akey=>c,
...
Practice it more and regularly, it will soon become easy for you to break complex structures into such combinations. This is how I created a large parser for another software, it is full of answers to your questions :)
With one peek at amon's up-voted comment above (thanks, amon!) I was able to write this little ditty:
#!/usr/bin/perl
# Given an array of hashes, print out the keys and values of each hash.
use strict; use warnings;
use Data::Dump qw(dump);
my $var1=[{A=>"B",C=>"D"},{E=>"F",G=>"H"}];
my $count = 0;
# #{$var1} is the array of hash references pointed to by $var1
foreach my $href (#{$var1})
{
print "\nArray index ", $count++, "\n";
print "=============\n";
# %{$href} is the hash pointed to by $href
foreach my $key (keys %{$href})
{
# $href->{$key} ( ALT: $$href{$key} ) is the value
# corresponding to $key in the hash pointed to by
# $href
# print $key, " => ", $href->{$key}, "\n";
print $key, " => ", $$href{$key}, "\n";
}
print "\nCompare with dump():\n";
dump ($var1);
print "\nJust the first hash (index 0):\n";
# $var1->[0] ( ALT: $$var1[0] ) is the first hash reference (index 0)
# in #{$var1}
# dump ($var1->[0]);
dump ($$var1[0]);
#print "\nJust the value of key A: \"", $var1->[0]->{A}, "\"\n";
#print "\nJust the value of key A: \"", $var1->[0]{A}, "\"\n";
print "\nJust the value of key A: \"", $$var1[0]{A}, "\"\n"

About the usage of hash reference in Perl

This reports syntax error:
$hash={a=>2};
print %{$hash}{a};
But this works:
print each(%{$hash})
Why??
To get an element from a hashref, you take the normal code for getting a hash element: $foo{'bar'}, and replace the name of the hash, not including the sigil, with the hashref: $$hash{'bar'}. Your % would only be used to dereference to the full hash, as in your each case, not just an element.
More helpful hints at http://perlmonks.org/?node=References+quick+reference.
Maybe this will help you understand why it's wrong...
$hash = {a => 2}; #Works: $hash is a reference to the hash
%foo = %{$hash}; #Now, we've dereferenced the hash to %foo
# Wherever we have "$hash", we can now use "foo"...
print %foo{a}; #Whoops! Doesn't work.
print %hash{a}; #And, neither did this!
print $foo{a}; #No problem! Use '$" when talking about a single hash element
print ${$hash}{a} #Same as above.
print each %foo; #Each takes a hash (with "%" sign)
print each %{$hash}; #Same as above.
print $hash->{a} #Syntactic Sugar: Same as ${$hash{a}} or $$hash{a}
Yeah, just like print %hash{a} doesn't work even though each(%hash) does.
each(%hash) ==> each(%{ $ref })
print($hash{a}) ==> print(${ $ref }{a})
You were missing the lookup '->'.
print %{$hash}{a};
should be:
print %{$hash}->{a};
You declare it as $ but then try to cast to a hash and retrieve the value, not sure why.
Just retrieve like so:
print $hash->{a};
My personal preference when it comes to hashes:
$hash1->{a} = 1;
print $hash1->{a}, "\n"; # prints '1'
Multi level:
$hash2->{a}{a} = 1;
$hash2->{a}{b} = 2;
print $hash2->{a}{a}, "\n"; # prints '1'
print $hash2->{a}{b}, "\n"; # prints '2'
Looping:
while (my ($key, $value) = each %{$hash1})
{
print $key, "\n"; # prints 'a'
print $value, "\n"; # prints '1'
}

What's the best practise for Perl hashes with array values?

What is the best practise to solve this?
if (... )
{
push (#{$hash{'key'}}, #array ) ;
}
else
{
$hash{'key'} ="";
}
Is that bad practise for storing one element is array or one is just double quote in hash?
I'm not sure I understand your question, but I'll answer it literally as asked for now...
my #array = (1, 2, 3, 4);
my $arrayRef = \#array; # alternatively: my $arrayRef = [1, 2, 3, 4];
my %hash;
$hash{'key'} = $arrayRef; # or again: $hash{'key'} = [1, 2, 3, 4]; or $hash{'key'} = \#array;
The crux of the problem is that arrays or hashes take scalar values... so you need to take a reference to your array or hash and use that as the value.
See perlref and perlreftut for more information.
EDIT: Yes, you can add empty strings as values for some keys and references (to arrays or hashes, or even scalars, typeglobs/filehandles, or other scalars. Either way) for other keys. They're all still scalars.
You'll want to look at the ref function for figuring out how to disambiguate between the reference types and normal scalars.
It's probably simpler to use explicit array references:
my $arr_ref = \#array;
$hash{'key'} = $arr_ref;
Actually, doing the above and using push result in the same data structure:
my #array = qw/ one two three four five /;
my $arr_ref = \#array;
my %hash;
my %hash2;
$hash{'key'} = $arr_ref;
print Dumper \%hash;
push #{$hash2{'key'}}, #array;
print Dumper \%hash2;
This gives:
$VAR1 = {
'key' => [
'one',
'two',
'three',
'four',
'five'
]
};
$VAR1 = {
'key' => [
'one',
'two',
'three',
'four',
'five'
]
};
Using explicit array references uses fewer characters and is easier to read than the push #{$hash{'key'}}, #array construct, IMO.
Edit: For your else{} block, it's probably less than ideal to assign an empty string. It would be a lot easier to just skip the if-else construct and, later on when you're accessing values in the hash, to do a if( defined( $hash{'key'} ) ) check. That's a lot closer to standard Perl idiom, and you don't waste memory storing empty strings in your hash.
Instead, you'll have to use ref() to find out what kind of data you have in your value, and that is less clear than just doing a defined-ness check.
I'm not sure what your goal is, but there are several things to consider.
First, if you are going to store an array, do you want to store a reference to the original value or a copy of the original values? In either case, I prefer to avoid the dereferencing syntax and take references when I can:
$hash{key} = \#array; # just a reference
use Clone; # or a similar module
$hash{key} = clone( \#array );
Next, do you want to add to the values that exist already, even if it's a single value? If you are going to have array values, I'd make all the values arrays even if you have a single element. Then you don't have to decide what to do and you remove a special case:
$hash{key} = [] unless defined $hash{key};
push #{ $hash{key} }, #values;
That might be your "best practice" answer, which is often the technique that removes as many special cases and extra logic as possible. When I do this sort of thing in a module, I typically have a add_value method that encapsulates this magic where I don't have to see it or type it more than once.
If you already have a non-reference value in the hash key, that's easy to fix too:
if( defined $hash{key} and ! ref $hash{key} ) {
$hash{key} = [ $hash{key} ];
}
If you already have non-array reference values that you want to be in the array, you do something similar. Maybe you want an anonymous hash to be one of the array elements:
if( defined $hash{key} and ref $hash{key} eq ref {} ) {
$hash{key} = [ $hash{key} ];
}
Dealing with the revised notation:
if (... )
{
push (#{$hash{'key'}}, #array);
}
else
{
$hash{'key'} = "";
}
we can immediately tell that you are not following the standard advice that protects novices (and experts!) from their own mistakes. You're using a symbolic reference, which is not a good idea.
use strict;
use warnings;
my %hash = ( key => "value" );
my #array = ( 1, "abc", 2 );
my #value = ( 22, 23, 24 );
push(#{$hash{'key'}}, #array);
foreach my $key (sort keys %hash) { print "$key = $hash{$key}\n"; }
foreach my $value (#array) { print "array $value\n"; }
foreach my $value (#value) { print "value $value\n"; }
This does not run:
Can't use string ("value") as an ARRAY ref while "strict refs" in use at xx.pl line 8.
I'm not sure I can work out what you were trying to achieve. Even if you remove the 'use strict;' warning, the code shown does not detect a change from the push operation.
use warnings;
my %hash = ( key => "value" );
my #array = ( 1, "abc", 2 );
my #value = ( 22, 23, 24 );
push #{$hash{'key'}}, #array;
foreach my $key (sort keys %hash) { print "$key = $hash{$key}\n"; }
foreach my $value (#array) { print "array $value\n"; }
foreach my $value (#value) { print "value $value\n"; }
foreach my $value (#{$hash{'key'}}) { print "h_key $value\n"; }
push #value, #array;
foreach my $key (sort keys %hash) { print "$key = $hash{$key}\n"; }
foreach my $value (#array) { print "array $value\n"; }
foreach my $value (#value) { print "value $value\n"; }
Output:
key = value
array 1
array abc
array 2
value 22
value 23
value 24
h_key 1
h_key abc
h_key 2
key = value
array 1
array abc
array 2
value 22
value 23
value 24
value 1
value abc
value 2
I'm not sure what is going on there.
If your problem is how do you replace a empty string value you had stored before with an array onto which you can push your values, this might be the best way to do it:
if ( ... ) {
my $r = \$hash{ $key }; # $hash{ $key } autoviv-ed
$$r = [] unless ref $$r;
push #$$r, #values;
}
else {
$hash{ $key } = "";
}
I avoid multiple hash look-ups by saving a copy of the auto-vivified slot.
Note the code relies on a scalar or an array being the entire universe of things stored in %hash.

How do I pass a hash to a function in Perl?

I have a function that takes a variable and an associative array, but I can't seem to get them to pass right. I think this has something to do with function declarations, however I can't figure out how they work in Perl. Is there a good reference for this and how do I accomplish what I need?
I should add that it needs to be passed by reference.
sub PrintAA
{
my $test = shift;
my %aa = shift;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
$aa{$_} = $aa{$_} . "+";
}
}
Pass the reference instead of the hash itself. As in
PrintAA("abc", \%fooHash);
sub PrintAA
{
my $test = shift;
my $aaRef = shift;
print $test, "\n";
foreach (keys %{$aaRef})
{
print $_, " : ", $aaRef->{$_}, "\n";
}
}
See also perlfaq7: How can I pass/return a {Function, FileHandle, Array, Hash, Method, Regex}?
This code works:
#!/bin/perl -w
use strict;
sub PrintAA
{
my($test, %aa) = #_;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
}
}
my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA );
PrintAA("test", %hash);
The key point is the use of the array context in the my() 'statement' in the function.
What does the array context business actually do?
Succinctly, it makes it work correctly.
It means that the first value in the #_ array of arguments is assigned to $test, and the remaining items are assigned to the hash %aa. Given the way I called it, there is an odd number of items in the #_, so once the first item is assigned to $test, there is an even number of items available to assign to %aa, with the first item of each pair being the key ('aaa', 'bbb', 'ccc' in my example), and the second being the corresponding value.
It would be possible to replace %aa with #aa, in which case, the array would have 6 items in it. It would also be possible to replace %aa with $aa, and in that case, the variable $aa would contain the value 'aaa', and the remaining values in #_ would be ignored by the assignment.
If you omit the parentheses around the variable list, Perl refuses to compile the code.
One of the alternative answers showed the notation:
my $test = shift;
my(%aa) = #_;
This is pretty much equivalent to what I wrote; the difference is that after the two my statements, #_ only contains 6 elements in this variation, whereas in the single my version, it still contains 7 elements.
There are definitely other questions in SO about array context.
Actually, I wasn't asking about the my($test, %aa) = #_; I was asking about my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA ); versus my %hash = { 'aaa' => 1, ... };
The difference is that the { ... } notation generates a hash ref and the ( ... ) notation generates a list, which maps to a hash (as opposed to hash ref). Similarly, [ ... ] generates an array ref and not an array.
Indeed, change the 'main' code so it reads: my(%hash) = { ... }; and you get a run-time (but not compile time) error - treat line numbers with caution since I've added alternative codings to my file:
Reference found where even-sized list expected at xx.pl line 18.
...
Use of uninitialized value in concatenation (.) or string at xx.pl line 13.
Alternatively:
sub PrintAA
{
my $test = shift;
my %aa = #_;
print $test . "\n";
foreach (keys %aa)
{
print $_ . " : " . $aa{$_} . "\n";
$aa{$_} = $aa{$_} . "+";
}
}
The thing you're fundamentally missing is that an associative array isn't a single argument (though an associative array reference is, as in Paul Tomblin's answer).
It looks like you should pass in a reference to a hash.
sub PrintAA
{
my $test = shift;
my $aa = shift;
if (ref($aa) != "HASH") { die "bad arg!" }
....
}
PrintAA($foo, \%bar);
The reason you can't do a
my %aa = shift;
is because Perl flattens all the arguments to a subroutine into one list, #_. Every element is copied, so passing in by reference avoids those copies as well.
As usual there are several ways. Here is what Perl Best Practices, that most revered of style pointers, has to say about passing parameters to functions:
Use a hash of named arguments for any subroutine that has more than three parameters
But since you have only two, you could get away ;) with passing them directly like this:
my $scalar = 5;
my %hash = (a => 1, b => 2, c => 3);
func($scalar, %hash)
And function is defined like this:
sub func {
my $scalar_var = shift;
my %hash_var = #_;
... Do something ...
}
It could be more useful if you could show some code.
All the methods in previous answers work, but this was always the way I preferred to do things like this:
sub PrintAA ($\%)
{
my $test = shift;
my %aa = ${shift()};
print "$test\n";
foreach (keys %aa)
{
print "$_ : $aa{$_}\n";
$aa{$_} = "$aa{$_}+";
}
}
Note: I also changed your code a bit. Perl's double-quoted strings will interpret "$test" to be the value of $test rather than the actual string '$test', so you don't need that many .s.
Also, I was wrong about how the prototypes work. To pass a hash, use this:
PrintAA("test", %hash);
To print a hash reference, use this:
PrintAA("test", %$ref_to_hash);
Of course, now you can't modify the hash referenced by $ref_to_hash because you're sending a copy, but you can modify a raw %hash because you're passing it as a reference.
Arguments to functions get flattened into a single array (#_). So it's usually easiest to pass hashes to a function by reference.
To create a hash:
my %myhash = ( key1 => "val1", key2 => "val2" );
To create a reference to that hash:
my $href = \%myhash
To access that hash by reference;
%$href
So in your sub:
my $myhref = shift;
keys %$myhref;
All the other replies here so far seem rather complicated to me. When I write Perl function I usually "expand" all the passed arguments in the first line of the function.
sub someFunction {
my ( $arg1, $arg2, $arg3 ) = #_;
This is similar to other languages, where you declare functions as
... someFunction ( arg1, arg2, arg3 )
And if you do it that way and pass the hash as the last argument, you'll be fine without any tricks or special magic. E.g.:
sub testFunc {
my ( $string, %hash ) = #_;
print "$string $hash{'abc'} $hash{'efg'} $string\n";
}
my %testHash = (
'abc' => "Hello,",
'efg' => "World!"
);
testFunc('!!!', %testHash);
The output is as expected:
!!! Hello, World! !!!
This works because in Perl arguments are always passed as an array of scalar values and if you pass a hash, its key value/pairs are added to that array. In the sample above, the arguments passed to the function as array (#_) are in fact:
'!!!', 'abc', 'Hello,', 'efg', 'World!'
and '!!!' is simply assigned to %string, while %hash "swallows" all the other arguments, always interpreting one as a key and the next one as value (until all elements are used up).
You cannot pass multiple hashes that way and the hash cannot be the first argument, as otherwise it would swallow everything and leave all other arguments unassigned.
Of course, exactly the same works for array as a last argument. The only difference here is that arrays don't distinguish between keys and values. For them, all arguments left over are values and just get pushed to the array.
Use the following sub to get the hash or hashref - whatever is passed :)
sub get_args { ref( $_[0] ) ? shift() : ( #_ % 2 ) ? {} : {#_}; }
sub PrintAA
{
my $test = shift;
my $aa = get_args(#_);;
# Then
$aa->{somearg} # Do something
$aa->{anotherearg} # Do something
}
Call your function like this:
printAA($firstarg,somearg=>1, anotherarg=>2)
Or like this (no matter):
printAA($firstarg, {somearg=>1, anotherarg=>2})
Or even like this (no matter):
my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \PrintAA );
PrintAA("test", %hash);