Traversing the hash of hash of array - perl

Here is by code :
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my $var = {
Cars => {
cars_name => [
"GT500",
"Beetle",
"P1800"
]
},
Bikes => {
Bikes_name => [
"Pulsar",
"Discover",
"CBR"
]
}
};
#Traversing the hash of hash of array
print "$var\n";
foreach my $k1 (keys %{$var}) {
print "$k1\n";
print $var->$k1;
#foreach my $k2 (keys %{$var->$k1}) {
#print"$k2\n";
#}
}
Whenever i am trying to print cars_name and Bikes_name , i am getting an error message saying the Can't call method Cars on Unblessed reference. I am not able to figure it out where am i doing mistake. Well, by mine understanding this print $var->$k1; line creating a prob. So please can any body help me out of this.
Thanks

print $var->$k1;
that is calling a method on an object. You want to access a hash:
print $var->{$k1};

Related

how to parse the output of SOAP response which is in HASH format of data? see below code for details

#perl!
use warnings;
use strict;
use XML::Compile::SOAP;
use XML::Compile::SOAP11;
use XML::Compile::WSDL11;
use XML::Compile::Transport::SOAPHTTP;
use Data::Dumper;
##my other variables pointing to wsdl and xsd files.
my $url="http://myhost.com:9080/imws/services/ImpactManager/";
my %inargs_connect = (
"userName" => "xxxx",
"password" => "xxxxxxxxxx",
"imname" => "yyyyyyyyyyy",
"bufferType" => "abcd"
);
my $wsdl = XML::Compile::WSDL11->new;
$wsdl->addWSDL($wsdl_file);
$wsdl->compileCalls(address =>$url);
my ($answer, $trace) = $wsdl->call( 'Connect', %inargs_connect);
print ($answer);
the above code is printing :
HASH(0x47f8b28)
in the last print statement if i use dumper, i get the below response.
print Dumper($answer);
$VAR1 = {
'outargs' => {
'connectionId' => '1557666855346'
}
};
how to parse the required values like,
i need to be able to easily access 'connectionId' and '1557666855346' ?
Any ideas are welcome. Thanks in advance.
Thanks,
Kaushik KM.
$answer appears to be a hash reference, so you'd access the data using normal dereferencing techniques:
my $conn_id = $answer->{outargs}{connectionId};
print "$conn_id\n";
Output:
1557666855346
my %fhash = %{$answer};
my $key = "";
foreach $key (keys %fhash)
{
print "keys are\n \"$key\" its value is (${$answer}{$key}) \n";
foreach my $key2 (keys %${$answer}{$key})
{
print "keys of(${$answer}{$key})\n \"$key2\"\n";
}
}
is not working and is throwing error as follows:
Experimental keys on scalar is now forbidden at CreateEvent.pl line 64.
Type of arg 1 to keys must be hash or array (not key/value hash slice) at Create
Event.pl line 64, near "}
can someone correct this please.
loop through all the keys in answear = { outargs => { key1, key2 }}
# This should remove the error of "Experimental keys on scalar is now forbidden" by wrapping the hashRef in %{}
for ( keys %{$answear->{outargs}}) {
# $_ here will be the key and if you want to access the value use $answear->{outargs}->{$_}
print "key: $_, value: $answear->{outargs}->{$_}\n";
}
output:
key: connectionId, value: 1557666855346
I hope this will help you!

Can I pass mix type of optional arguments to a subroutine?

I am trying to pass a hash and optional list of variables to a subroutine in hash but its not working. Could you please correct below sample code to help me with the approach?
My sample code looks like
#!/bin/env perl
use warnings;
use strict;
use Data::Dumper;
my %h1 = ( a=> 2, b=>3);
sub sum {
my $var1=shift;
my $var2=shift;
my %hash1=#_;
#my($a,$b)=#_;
my $i=0;
foreach my $val (keys %hash1) {
$i=$i+$hash1{$val};
}
if ( not defined $var2 ) {
return ($i+$var1);
} else {
return ($i+$var1+$var2);
}
}
my $c=sum(3,%h1);
print $c;
You call your subroutine like this:
my $c=sum(3,%h1);
And inside your subroutine, you access the parameters like this:
my $var1=shift;
my $var2=shift;
my %hash1=#_;
There seems to be an obvious discrepancy here. You're passing a scalar and a hash to the subroutine, but inside your subroutine, you're expecting two scalars and a hash.
So perhaps it will work as you expect it to if you remove the my $var2 = shift line.
It's not really clear what your subroutine is meant to do. If you were to explain that, then we could probably be a little more help.
Update: You have Data::Dumper in your code. Why not use it to try to understand what is going on.
print Dumper(\#_), "\n";
my $var1=shift;
my $var2=shift;
my %hash1=#_;
print Dumper($var1, $var2, \%hash1), "\n";
I get:
$VAR1 = [
3,
'b',
3,
'a',
2
];
Odd number of elements in hash assignment at test line 11.
$VAR1 = 3;
$VAR2 = 'b';
$VAR3 = {
'3' => 'a',
'2' => undef
};
Which shows a couple of interesting things:
The hash being "unrolled" into a list before being put into #_.
The warning you get when you initialise a hash from a list with an odd number of elements.
Your %hash1 variable with incorrect keys and values.
Thanks everyone. This is how we can pass optional arguments to a subroutine in perl with type mixed
#!/bin/env perl
use warnings;
use strict;
use Data::Dumper;
my %h1 = ( a=> 2, b=>3);
sub sum {
my ($hash1,$var1,$var2)=#_;
#my($a,$b)=#_;
my $i=0;
foreach my $val (keys %{$hash1}) {
$i=$i+$hash1->{$val};
}
if (defined $var2 ) {
return ($i+$var1+$var2);
} else {
return ($i+$var1);
}
}
my $c=sum(\%h1,3);
print $c;
Please correct me if I missed something.
Regards,
Divesh
#!/usr/bin/perl
use warnings;
use strict;
use JSON;
use feature qw(say);
args_in( 'test', { foo => 'bar' }, ["one", "two", "three"] );
sub args_in {
my $args_aref = parse_args( #_ );
say to_json $args_aref;
}
sub parse_args {
my #ary;
foreach( #_ ) {
my %hash;
if (ref $_) {
$hash{type} = ref $_;
} else {
$hash{type} = 'SCALAR';
}
$hash{value} = $_;
push #ary, \%hash;
}
return \#ary;
}
Results:
[
{
"value": "test",
"type": "SCALAR"
},
{
"value": {
"foo": "bar"
},
"type": "HASH"
},
{
"value": [
"one",
"two",
"three"
],
"type": "ARRAY"
}
]

Understanding Data::Dumper output

Simple question:
use warnings;
use XML::Simple;
use Data::Dumper;
my $file='test.osm';
my $test_data = XMLin( $file );
print Dumper( $test_data );
my #way_node_refs=$test_data->{'way'}->{'nd'};
print Dumper( #way_node_refs );
print( #way_node_refs[1]->{'ref'} );ere
It has the following output. The first dump is not given because it does not matter.
$VAR1 = [
{
'ref' => '453966480'
},
{
'ref' => '453966490'
},
{
'ref' => '453966482'
},
{
'ref' => '453966130'
},
{
'ref' => '453966143'
},
{
'ref' => '453966480'
}
];
How can I access the values with the key ref. I don't know how to interprete the braces kinda.
This is called array of hashes. If $array contains the data then below will work :
[] is anonymous array reference, while {} is anonymous hash reference. Check perlref.
for (#{ $array }) {
print $_ -> {ref},"\n";
}
Further reading:
Using Arrow operator(->) - Most suitable for accesing a single item from arrayref or hashref.
Using # { } - Suitable for iterating over arrayrefs .
Edit:
Now after your edit, it is clear that you want something like this:
for (#way_node_refs) {
print $_ -> {ref},"\n";
}
You have an array reference where the values inside the array are hash references. To access single values, use the arrow operator ->.
print $foo->[0]->{ref};
print $foo->[1]->{ref};
Or you can loop through them.
foreach my $elem ( #{ $foo } ) {
print Dumper $elem;
print $elem->{ref};
}
You could even sort them alphabetically by the values of the ref keys.
my #sorted = sort { $a->{ref} cmp $b->{ref} } #$foo; # note #sorted is an array
See perlref, perlreftut and perldsc for more details on data structures and references.

Hash doesn't print in Perl

I have a hash:
while( my( $key, $value ) = each %sorted_features ){
print "$key: $value\n";
}
but I cannot obtain the correct value for $value. It gives me:
intron: ARRAY(0x3430440)
source: ARRAY(0x34303b0)
exon: ARRAY(0x34303f8)
sig_peptide: ARRAY(0x33f0a48)
mat_peptide: ARRAY(0x3430008)
Why is it?
Your values are array references. You need to do something like
while( my( $key, $value ) = each %sorted_features ) {
print "$key: #$value\n";
}
In other words, dereference the reference. If you are unsure what your data looks like, a good idea is to use the Data::Dumper module:
use Data::Dumper;
print Dumper \%sorted_features;
You will see something like:
$VAR1 = {
'intron' => [
1,
2,
3
]
};
Where { denotes the start of a hash reference, and [ an array reference.
You can use also Data::Dumper::Pertidy which runs the output of Data::Dump through Perltidy.
#!/usr/bin/perl -w
use strict;
use Data::Dumper::Perltidy;
my $data = [{title=>'This is a test header'},{data_range=>
[0,0,3, 9]},{format => 'bold' }];
print Dumper $data;
Prints:
$VAR1 = [
{ 'title' => 'This is a test header' },
{ 'data_range' => [ 0, 0, 3, 9 ] },
{ 'format' => 'bold' }
];
Your hash values are array references. You need to write additional code to display the contents of these arrays, but if you are just debugging then it is probably simpler to use Data::Dumper like this
use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper \%sorted_features;
And, by the way, the name %sorted_features of your hash worries me. hashes are inherently unsorted, and the order that each retrieves the elements is essentially random.

Hash dereference in Perl

I have a HASH reference $job which has this data:
{
"opstat" : "ok",
"response": {
"group_id":23015,
"order_id":"139370",
"job_count":"10",
"credits_used":"100.45",
"currency":"USD"
}
}
I want to print the hash value of "response" key.
I tried doing this but did not work
print %{$job->{'response'}}
Edit
I do not want any formatting. I want to know how to access each element in the value of 'response' key.
I want to know how to access each element in the value of 'response' key.
By definition, you need some kind of loop. A foreach loop is typical, although you could also use map.
for my $key (keys %{$job->{response}}) {
my $val = $job->{response}{$key};
print("$key: $val\n"); # Or whatever
}
or
my $response = $job->{response};
for my $key (keys %$response) {
my $val = $response->{$key};
print("$key: $val\n"); # Or whatever
}
Try the following code, this is a real & complete script :
#!/usr/bin/env perl
use strict;
use warnings;
my $job = {
'opstat' => 'ok',
'response' => {
'currency' => 'USD',
'group_id' => ':23015',
'job_count' => '10',
'order_id' => '139370',
'credits_used' => '100.45'
}
};
foreach my $key (keys %{$job}) {
print "key=$key|value=$job->{$key}\n";
# Testing if "$job->{$key}" is a HASH ref
# ...if yes, we iterate inside the HASH
# through the next level.
if (ref($job->{$key}) eq "HASH") {
foreach my $key2 (keys %{$job->{$key}}) {
print "\tkey=$key2|value=$job->{$key}->{$key2}\n";
}
}
}
This is the output :
key=opstat|value=ok
key=response|value=HASH(0x1638998)
key=currency|value=USD
key=group_id|value=:23015
key=order_id|value=139370
key=job_count|value=10
key=credits_used|value=100.45
If you want to access "group_id" key :
print $job->{response}->{group_id};
If you only want to access "response" HASH without testing anything :
foreach my $key (keys %{$job->{response}}) {
print "key=$key|value=$job->{response}->{$key}\n";
}
or with with this while loop and each :
while (my ($key,$value) = each %{$job->{response}}){
print "key=$key|value=$value\n";
}
use Data::Dumper;
print Dumper( $job->{response} );
or individually ...
print $job->{response}{group_id};
I'm not quite sure what you're trying to achieve; your code would print the contents of the inner hash without any formatting. If you want a formatted output, you'd have to use the Data::Dumper module:
use Data::Dumper;
my $job = {
"opstat" => "ok",
"response" => {
"group_id":23015,
"order_id":"139370",
"job_count":"10",
"credits_used":"100.45",
"currency":"USD"
}
};
print Dumper($job->{'response'});