I am new to perl and i had written below snippet of code to get the JSON objects from the data. But the input data has both hashes and arrays, So how do i get those values for "id" which is an array ?
use strict;
use warnings;
use Data::Dumper;
use JSON
my $data = '{"total":325,"id": [78,234,737,1253,1459,1733,2166,2653,2855,3133,3414,3538,3729,3905,3991,4110,4160,4536,4692,4701]}';
print Dumper($data);
my #hash_ref = from_json($data);
foreach my $hash_scalar (#hash_ref) {
foreach (keys %{$hash_scalar}) {
print "$_ => ${$hash_scalar}{$_}\n";
}
}
Output Getting
#
$VAR1 = '{"total":325,"id":
[78,234,737,1253,1459,1733,2166,2653,2855,3133,3414,3538,3729,3905,3991,4110,4160,4536,4692,4701]}';
id => ARRAY(0x2afee4c)
total => 325
The id is a key in the hash reference you get back, and you want to grab its value, which is an array reference. You can either keep that as a reference or grab its elements right away:
#!perl
use v5.24;
use JSON qw(from_json);
my $data = '{"total":325,"id": [78,234,737]}';
my $json = from_json($data);
# get the hash key to get the hash value, which is an array reference
my $ids_array_ref = $json->{id};
# OR, use the postfix dereference to get the ids as a normal list
my #ids_array = $json->{id}->#*;
# OR, use the older circumfix notation (before Perl v5.24). These are all
# the same:
my #ids_array = #{ $json->{id} };
my #ids_array = #{ $ids_array_ref };
my #ids_array = #$ids_array_ref;
For example:
#!perl
use v5.24;
use JSON qw(from_json);
my $data = '{"total":325,"id": [78,234,737]}';
my $json = from_json($data);
foreach my $id ( $json->{id}->#* ) {
say "Got id $id";
}
This outputs:
Got id 78
Got id 234
Got id 737
But, you have to handle the other hash value types too. To decide how to print something, you have to check if it's a reference and what sort of reference it is (I ignore the other sorts here):
#!perl
use v5.24;
use JSON qw(from_json);
my $data = '{"total":325,"id": [78,234,737]}';
my $json = from_json($data);
foreach my $key ( keys $json->%* ) {
print "$key: ";
if( ref $json->{$key} eq 'ARRAY' ) {
say join ' ', $json->{$key}->#*;
}
elsif( ref $json->{$key} ) { # all other reference types
warn "I don't handle this yet"
}
else {
say $json->{$key};
}
}
But, you might have deeper levels of nesting, so you'd need to think about that too if you want to output everything. If I know what keys I want, I don't try to go through everything in a general way. I go directly to want I want:
#!perl
use v5.24;
use JSON qw(from_json);
my $data = '{"total":325,"id": [78,234,737]}';
my $json = from_json($data);
say "id: ", join ' ', $json->{id}->#*;
say "total: ", $json->{total};
Your original code was doubly complicated. The result of from_json is the reference that represents the JSON data structure. That's a JSON object, which is what Perl calls a hash, so you get a hash reference back.
my $hash_ref = from_json( $data );
Your example almost worked because you got an array of one element, which is that hash reference. The other foreach then iterates over that one element. Get rid of that outer array and you get rid of the outer loop.
We cover references and data structures in Intermediate Perl, although the perldsc is good too. We have a long examples of deeply-nested and recursive data structures.
If you're new, you may want to start with Learning Perl, though.
My Perl is getting rusty, but I think something like this should do the trick. You need to de-reference your array reference with another #{...} like #{${$hash_scalar}{$_}}.
use strict;
use warnings;
use Data::Dumper;
use JSON
my $data = '{"total":325,"id": [78,234,737,1253,1459,1733,2166,2653,2855,3133,3414,3538,3729,3905,3991,4110,4160,4536,4692,4701]}';
print Dumper($data);
my #hash_ref = from_json($data);
for my $hash_scalar (#hash_ref) {
for my $key (keys(%{$hash_scalar})) {
print("$key => #{${$hash_scalar}{$_}}\n");
}
}
Perhaps following code will cover your question in more complete extent.
NOTE: I've added a hash in data block as bonus
use strict;
use warnings;
use feature 'say';
use JSON;
use Data::Dumper;
my $debug = 0;
my $data = '{ "total":325,
"id": [78,234,737,1253,1459,1733,2166,2653,2855,3133,3414,3538,3729,3905,3991,4110,4160,4536,4692,4701],
"person": {
"first": "John",
"last": "Smith",
"age": 27,
"occupation": "accountant",
"wife": "Maria Smith",
"son": "Alex Smith",
"daughter": "Samantha Smith",
"dog": "Sparky",
"hobby": "photography"
}
}';
say Dumper($data) if $debug;
my $json = from_json($data);
say Dumper($json) if $debug;
while( my($k,$v) = each %{$json} ) {
say "Key: $k";
if( ref $v eq 'ARRAY' ) {
say "\tValue is ARRAY";
for ( #{$v} ) { say "\t\t[$_]" }
} elsif( ref $v eq 'HASH' ) {
say "\tValue is HASH";
while( my($hk,$hv) = each %{$v} ) {
say "\t\t$hk => $hv";
}
} else {
say "\tValue: $v";
}
}
say '-' x 40;
say 'Element with index 5 is ' . $json->{id}[5];
say 'Name of the son is ' . $json->{person}{son};
say 'Name of the daughter is ' . $json->{person}{daughter};
Output
Key: person
Value is HASH
son => Alex Smith
occupation => accountant
daughter => Samantha Smith
age => 27
wife => Maria Smith
dog => Sparky
last => Smith
first => John
hobby => photography
Key: id
Value is ARRAY
[78]
[234]
[737]
[1253]
[1459]
[1733]
[2166]
[2653]
[2855]
[3133]
[3414]
[3538]
[3729]
[3905]
[3991]
[4110]
[4160]
[4536]
[4692]
[4701]
Key: total
Value: 325
----------------------------------------
Element with index 5 is 1733
Name of the son is Alex Smith
Name of the daughter is Samantha Smith
I'm trying to make subroutine closure working like an object.
However, I cannot call the returned subs references properly.
I receive Not a CODE reference at .\closure.pl line 22. error.
#!/usr/bin/perl
use strict;
use warnings;
sub number {
my ($value) = #_;
my $val = sub { $value };
my $inc = sub { ++$value };
my $dec = sub { --$value };
my %api = (
'val' => \$val,
'inc' => \$inc,
'dec' => \$dec,
);
return %api;
}
my %numb = number(42);
$numb{'inc'}->();
print $numb{'val'}->();
How to fix the code?
Code fixed
Yes, of course, an anonymous definition must return a reference. it means that it can be put directly in the %api. Perl doesn't complain and works like a charm :)
#!/usr/bin/perl
use strict;
use warnings;
sub number {
my ($value) = #_;
my %api = (
'val' => sub { $value },
'inc' => sub { ++$value },
'dec' => sub { --$value },
);
return \%api;
}
my $m = number(14);
my $n = number(41);
$m->{'dec'}->();
$n->{'inc'}->();
print $m->{'val'}->() . "\n"; # -> 13
print $n->{'val'}->() . "\n"; # -> 42
As discussed in perlref, the sub keyword without a name creates an anonymous subroutine and returns a reference to it. So you don't need to create another level of reference using the backslash; just pass the reference you already have as the value in the hash.
How would one determine the subroutine name of a Perl code reference? I would also like to distinguish between named and anonymous subroutines.
Thanks to this question I know how to print out the code, but I still don't know how to get the name.
For example, I'd like to get 'inigo_montoya' from the following:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
my $sub_ref = \&inigo_montoya;
print Dumper $sub_ref;
# === subroutines ===
sub inigo_montoya {
print <<end_quote;
I will go up to the six-fingered man and say, "Hello. My name is Inigo
Montoya. You killed my father. Prepare to die."';
end_quote
}
Why not ask, what the compiler sees? (It would return __ANON__ on anonymous subs).
#!/usr/bin/perl
use strict;
use warnings;
my $sub_ref = \&inigo_montoya;
use B qw(svref_2object);
my $cv = svref_2object ( $sub_ref );
my $gv = $cv->GV;
print "name: " . $gv->NAME . "\n";
sub inigo_montoya {
print "...\n";
}
Sub::Identify does exactly this, hiding all that nasty B::svref_2object() stuff from you so you don't have to think about it.
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Sub::Identify ':all';
my $sub_ref = \&inigo_montoya;
say "Sub Name: ", sub_name($sub_ref);
say "Stash Name: ", stash_name($sub_ref);
say "Full Name: ", sub_fullname($sub_ref);
# === subroutines ===
sub inigo_montoya {
print <<' end_quote';
I will go up to the six-fingered man and say, "Hello. My name is Inigo
Montoya. You killed my father. Prepare to die."';
end_quote
}
Which outputs:
$ ./sub_identify.pl
Sub Name: inigo_montoya
Stash Name: main
Full Name: main::inigo_montoya
Expanding on Jan Hartung's idea (and scrapping my own), you could get a fully qualified name and some trace information for no matter what it is or where it came from:
use B qw(svref_2object);
sub sub_name {
return unless ref( my $r = shift );
return unless my $cv = svref_2object( $r );
return unless $cv->isa( 'B::CV' )
and my $gv = $cv->GV
;
my $name = '';
if ( my $st = $gv->STASH ) {
$name = $st->NAME . '::';
}
my $n = $gv->NAME;
if ( $n ) {
$name .= $n;
if ( $n eq '__ANON__' ) {
$name .= ' defined at ' . $gv->FILE . ':' . $gv->LINE;
}
}
return $name;
}
I'm not sure about calling the name of the function from the outside, but you can get it from within the subroutine via the caller function:
sub Foo {print "foo!\n";return (caller(0))[3];}
$function_name=Foo();
print "Called $function_name\n";
This has the following output:
foo!
Called main::Foo
Of course, you can return the function name as one of the items that the subroutine returns. That way, you can capture it and have the option of displaying it (or using it in other logic, etc).
How would one determine the subroutine name of a Perl code reference? I would also like to distinguish between named and anonymous subroutines.
Thanks to this question I know how to print out the code, but I still don't know how to get the name.
For example, I'd like to get 'inigo_montoya' from the following:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
my $sub_ref = \&inigo_montoya;
print Dumper $sub_ref;
# === subroutines ===
sub inigo_montoya {
print <<end_quote;
I will go up to the six-fingered man and say, "Hello. My name is Inigo
Montoya. You killed my father. Prepare to die."';
end_quote
}
Why not ask, what the compiler sees? (It would return __ANON__ on anonymous subs).
#!/usr/bin/perl
use strict;
use warnings;
my $sub_ref = \&inigo_montoya;
use B qw(svref_2object);
my $cv = svref_2object ( $sub_ref );
my $gv = $cv->GV;
print "name: " . $gv->NAME . "\n";
sub inigo_montoya {
print "...\n";
}
Sub::Identify does exactly this, hiding all that nasty B::svref_2object() stuff from you so you don't have to think about it.
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Sub::Identify ':all';
my $sub_ref = \&inigo_montoya;
say "Sub Name: ", sub_name($sub_ref);
say "Stash Name: ", stash_name($sub_ref);
say "Full Name: ", sub_fullname($sub_ref);
# === subroutines ===
sub inigo_montoya {
print <<' end_quote';
I will go up to the six-fingered man and say, "Hello. My name is Inigo
Montoya. You killed my father. Prepare to die."';
end_quote
}
Which outputs:
$ ./sub_identify.pl
Sub Name: inigo_montoya
Stash Name: main
Full Name: main::inigo_montoya
Expanding on Jan Hartung's idea (and scrapping my own), you could get a fully qualified name and some trace information for no matter what it is or where it came from:
use B qw(svref_2object);
sub sub_name {
return unless ref( my $r = shift );
return unless my $cv = svref_2object( $r );
return unless $cv->isa( 'B::CV' )
and my $gv = $cv->GV
;
my $name = '';
if ( my $st = $gv->STASH ) {
$name = $st->NAME . '::';
}
my $n = $gv->NAME;
if ( $n ) {
$name .= $n;
if ( $n eq '__ANON__' ) {
$name .= ' defined at ' . $gv->FILE . ':' . $gv->LINE;
}
}
return $name;
}
I'm not sure about calling the name of the function from the outside, but you can get it from within the subroutine via the caller function:
sub Foo {print "foo!\n";return (caller(0))[3];}
$function_name=Foo();
print "Called $function_name\n";
This has the following output:
foo!
Called main::Foo
Of course, you can return the function name as one of the items that the subroutine returns. That way, you can capture it and have the option of displaying it (or using it in other logic, etc).
I would like to have a subroutine as a member of a hash which is able to have access to other hash members.
For example
sub setup {
%a = (
txt => "hello world",
print_hello => sub {
print ${txt};
})
return %a
}
my %obj = setup();
$obj{print_hello};
Ideally this would output "hello world"
EDIT
Sorry, I failed to specify one requirement
I should be able to do
$obj{txt} = "goodbye";
and then $obj{print_hello} should output goodbye
If you want the calling code to be able to modify the message in the hash, you need to return the hash by reference. This does what you asked for:
use strict;
use warnings;
sub self_expressing_hash {
my %h;
%h = (
msg => "hello",
express_yourself => sub { print $h{msg}, "\n" },
);
return \%h;
}
my $h = self_expressing_hash();
$h->{express_yourself}->();
$h->{msg} = 'goodbye';
$h->{express_yourself}->();
However, it's a bizarre concoction -- essentially, a data structure that contains some built-in behavior. Sounds a like an object to me. Perhaps you should look into an O-O approach for your project.
This will work:
sub setup {
my %a = ( txt => "hello world" );
$a{print_hello} = sub { print $a{txt} };
return %a;
}
my %obj = setup();
$obj{print_hello}->();
Close:
sub setup {
my %a = (
txt => "hello world",
print_hello => sub {
print $a{txt};
});
return %a;
}
my %obj = setup();
$obj{print_hello}->();