I have this code:
$coder = JSON::XS->new->utf8->pretty->allow_nonref;
%perl = $coder->decode ($json);
When I write print %perl variable it says HASH(0x9e04db0). How can I access data in this HASH?
As the decode method actually returns a reference to hash, the proper way to assign would be:
%perl = %{ $coder->decode ($json) };
That said, to get the data from the hash, you can use the each builtin or loop over its keys and retrieve the values by subscripting.
while (my ($key, $value) = each %perl) {
print "$key = $value\n";
}
for my $key (keys %perl) {
print "$key = $perl{$key}\n";
}
JSON::XS->decode returns a reference to an array or a hash. To do what you are trying to do you would have to do this:
$coder = JSON::XS->new->utf8->pretty->allow_nonref;
$perl = $coder->decode ($json);
print %{$perl};
In other words, you'll have to dereference the hash when using it.
The return value of decode isn't a hash and you shouldn't be assigning it to a %hash -- when you do, you destroy its value. It's a hash reference and should be assigned to a scalar. Read perlreftut.
You need to specify the particular key of hash, Then only you will be able to access the data from the hash .
For example if %perl hash has key called 'file' ;
You suppose to access like below
print $perl{'file'} ; # it would print the file key value of the %perl hash
Lots of ways, you can use a foreach loop
foreach my $key (%perl)
{
print "$key is $perl{$key}\n";
}
or a while loop
while (my ($key, $value) = each %perl)
{
print "$key is $perl{$key}\n";
}
Related
I am trying to create a hash of array. Currently the array is of size 1 only.
$f1="/scratch/aime1/PerlCode/BeforeUpgrade.csv";
$f2="/scratch/aime1/PerlCode/AfterUpgrade.csv";
open(FIN, "< $f1");
while( $my_line = <FIN> )
{
chomp $my_line;
my #values = split(',', $my_line);
my $key = shift #values;
print "$key\n";
print "#values\n";
$hash1{$key} = #values;
}
close(FIN);
for (keys %hash1) {
my #value_array = $hash1{$_};
print "Key is $_ and first Element of array is $value_array[0] \n";
}
So,the key is of the form /scratch/aime1/idmUpgrade/idmUpgrade and the value is its permission i.e. 0755
When I try to print this hash,output is:
Key is /scratch/aime1/idmUpgrade/idmUpgrade and first Element of array is 1
Array is always printed as 1 and not as 0755.
Always include use strict; and use warnings; at the top of EVERY perl script.
You're assigning an array to a hash key, to do that you need to take a reference. Otherwise, you're just assigning the array count (which is 1)
$hash1{$key} = \#values;
Similarly, when you want to retrieve, it, you'll need to dereference it:
my #value_array = #{$hash1{$_}};
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 :-)
foreach my %hash (%myhash1,%myhash2,%myhash3)
{
while (($keys,$$value) = each %hash)
{
#use key and value...
}
}
Why doesn't this work :
it says synta error on foreach line.
Pls tell me why is it wrong.
This is wrong because you seem to think that this allows you to access each hash as a separate construct, whereas what you are in fact doing is, besides a syntax error, accessing the hashes as a mixed-together new list. For example:
my %hash1 = qw(foo 1 bar 1);
my %hash2 = qw(abc 1 def 1);
for (%hash1, %hash2) # this list is now qw(foo 1 bar 1 abc 1 def 1)
When you place a hash (or array) in a list context statement, they are expanded into their elements, and their integrity is not preserved. Some built-in functions do allow this behaviour, but normal Perl code does not.
You also cannot assign a hash as the for iterator variable, that can only ever be a scalar value. What you can do is this:
for my $hash (\%myhash1, \%myhash2, \%myhash3) {
while (my ($key, $value) = each %$hash) {
...
Which is to say, you create a list of hash references and iterate over them. Note that you cannot tell the difference between the hashes with this approach.
Note also that I use my $hash because this variable must be a scalar.
The syntax should be like:
my $hash1 = {'a'=>1};
my $hash2 = {'b'=>1};
my #arr2 = ($hash1, $hash2);
foreach $hash (#arr2)
{
while(($key, $value) = each %$hash)
{
print $key, $value;
}
}
you need to reference and then dereference the hash.
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"
Is there a simple way to validate a hash of hash element comparsion ?
I need to validate a Perl hash of hash element $Table{$key1}{$key2}{K1}{Value} compare to all other elements in hash
third key will be k1 to kn and i want comprare those elements and other keys are same
if ($Table{$key1}{$key2}{K1}{Value} eq $Table{$key1}{$key2}{K2}{Value}
eq $Table{$key1}{$key2}{K3}{Value} )
{
#do whatever
}
Something like this may work:
use List::MoreUtils 'all';
my #keys = map "K$_", 1..10;
print "All keys equal"
if all { $Table{$key1}{$key2}{$keys[1]}{Value} eq $Table{$key1}{$key2}{$_}{Value} } #keys;
I would use Data::Dumper to help with a task like this, especially for a more general problem (where the third key is more arbitrary than 'K1'...'Kn'). Use Data::Dumper to stringify the data structures and then compare the strings.
use Data::Dumper;
# this line is needed to assure that hashes with the same keys output
# those keys in the same order.
$Data::Dumper::Sortkeys = 1;
my $string1= Data::Dumper->Dump($Table{$key1}{$key2}{k1});
for ($n=2; exists($Table{$key1}{$key2}{"k$n"}; $n++) {
my $string_n = Data::Dumper->Dump($Table{$key1}{$key2}{"k$n"});
if ($string1 ne $string_n) {
warn "key 'k$n' is different from 'k1'";
}
}
This can be used for the more general case where $Table{$key1}{$key2}{k7}{value} itself contains a complex data structure. When a difference is detected, though, it doesn't give you much help figuring out where that difference is.
A fairly complex structure. You should be looking into using object oriented programming techniques. That would greatly simplify your programming and the handling of these complex structures.
First of all, let's simplify a bit. When you say:
$Table{$key1}{$key2}{k1}{value}
Do you really mean:
my $value = $Table{$key1}->{$key2}->{k1};
or
my $actual_value = $Table{$key1}->{$key2}->{k1}->{Value};
I'm going to assume the first one. If I'm wrong, let me know, and I'll update my answer.
Let's simplify:
my %hash = %{$Table{$key1}->{$key2}};
Now, we're just dealing with a hash. There are two techniques you can use:
Sort the keys of this hash by value, then if two keys have the same value, they will be next to each other in the sorted list, making it easy to detect duplicates. The advantage is that all the duplicate keys would be printed together. The disadvantage is that this is a sort which takes time and resources.
Reverse the hash, so it's keyed by value and the value of that key is the key. If a key already exists, we know the other key has a duplicate value. This is faster than the first technique because no sorting is involved. However, duplicates will be detected, but not printed together.
Here's the first technique:
my %hash = %{$Table{$key1}->{$key2}};
my $previous_value;
my $previous_key;
foreach my $key (sort {$hash{$a} cmp $hash{$b}} keys %hash) {
if (defined $previous_key and $previous_value eq $hash{$key}) {
print "\$hash{$key} is a duplicate of \$hash{$previous_key}\n";
}
$previous_value = $hash{$key};
$previous_key = $key;
}
And the second:
my %hash = %{$Table{$key1}->{$key2}};
my %reverse_hash;
foreach $key (keys %hash) {
my $value = $hash{$key};
if (exists $reverse_hash{$value}) {
print "\$hash{$reverse_hash{$value}} has the same value as \$hash{$key}\n";
}
else {
$reverse_hash{$value} = $key;
}
}
Alternative approach to the problem is make utility function which will compare all keys if has same value returned from some function for all keys:
sub AllSame (&\%) {
my ($c, $h) = #_;
my #k = keys %$h;
my $ref;
$ref = $c->() for $h->{shift #k};
$ref ne $c->() and return for #$h{#k};
return 1
}
print "OK\n" if AllSame {$_->{Value}} %{$Table{$key1}{$key2}};
But if you start thinking in this way you can found this approach much more generic (recommended way):
sub AllSame (#) {
my $ref = shift;
$ref ne $_ and return for #_;
return 1
}
print "OK\n" if AllSame map {$_->{Value}} values %{$Table{$key1}{$key2}};
If mapping operation is expensive you can make lazy counterpart of same:
sub AllSameMap (&#) {
my $c = shift;
my $ref;
$ref = $c->() for shift;
$ref ne $c->() and return for #_;
return 1
}
print "OK\n" if AllSameMap {$_->{Value}} values %{$Table{$key1}{$key2}};
If you want only some subset of keys you can use hash slice syntax e.g.:
print "OK\n" if AllSame map {$_->{Value}} #{$Table{$key1}{$key2}}{map "K$_", 1..10};