How to get data from Perl data structure - perl

I've parsed JSON into the following data structure:
$VAR1 = {
'041012020' => {
'item_number' => 'P2345'
},
'041012021' => {
'item_number' => 'I0965'
},
'041012022' => {
'item_number' => 'R2204'
}
};
I'm trying to get the values of item_numbers using the following code, and it's giving me the HASH Values as output rather than the actual item_number values. Please guide me to get the expected values.
foreach my $value (values %{$json_obj}) {
say "Value is: $value,";
}
Output:
Value is: HASH(0x557ce4e2f3c0),
Value is: HASH(0x557ce4e4de18),
Value is: HASH(0x557ce4e4dcf8),
If I use the same code to get the keys it's working perfectly fine
foreach my $key (keys %{$json_obj}) {
say "Key is: $key,";
}
Output:
Key is: 041012020,
Key is: 041012020,
Key is: 041012022,

The values of the hash elements are references to hashes ({ item_number => 'P2345' }). That's what you get when you stringify a reference. If you want the item number, you'll need to tell Perl that.
for my $value (values %$data) {
say $value->{item_number};
}
or
for my $item_number ( map { $_->{item_number} } values %$data ) {
say $item_number;
}

Here is the short code for your question.
#!usr/bin/perl
$VAR1 = {
'041012020' => {
'item_number' => 'P2345'
},
'041012021' => {
'item_number' => 'I0965'
},
'041012022' => {
'item_number' => 'R2204'
}
};
print "$VAR1->{$_}->{item_number}\n" for keys %$VAR1;
To use for in a block:
for my $key (keys %$VAR1) {
print "$VAR1->{$key}->{item_number}\n"
}

Related

Perl Sort Perl hash of hash like structure by values

I have this structure:
'$self' => {
'stepTimePercentage' =>{
'id12' => {
'percentage' => '1.00'
},
'id15' => {
'percentage' => '30.00'
},
'id4' => {
'percentage' => '20.00'
},
'id9' => {
'percentage' => '15.00'
},
}
}
I want to sort this structure by the values of the 'percentage'. I tryed the following but i get the : "Use of uninitialized value in numeric comparison (<=>)".
foreach my $key (sort{ $self->{stepTimePercentage}->{percentage}{$b} <=> $self->{stepTimePercentage}->{percentage}{$a} } keys %{$self->{stepTimePercentage}}) {
print "$key - $self->{stepTimePercentage}->{$key}->{percentage} % \n";
}
Then I tryed this (and i get "Global symbol "$key" requires explicit package name"):
foreach my $key (sort{ $self->{stepTimePercentage}{key}{$b} <=> $self->{stepTimePercentage}{$key}{$a}} keys %{$self->{stepTimePercentage}}) {
print ("$key - $self->{stepTimePercentage}->{$key}->{percentage} % \n");
}
You're almost there. The key you are sorting on is at the second level of a three-level hash, so you want:
foreach my $key (sort {
$self->{stepTimePercentage}{$b}{percentage}
<=>
$self->{stepTimePercentage}{$a}{percentage}
} keys %{$self->{stepTimePercentage}}) {
print "$key - $self->{stepTimePercentage}->{$key}->{percentage} % \n";
}

executing a function within an array within a hash in perl

I have a Perl data structurte like so
%myhash = (
k1 => v1,
kArray => [
{
name => "anonymous hash",
...
},
\&funcThatReturnsHash,
{
name => "another anonymous hash",
...
}
]
);
Elsewhere I iterate through the list in kArray which contains a bunch of hashes. I would like to either process the actual hash OR the hash returned by the function.
foreach my $elem( #{myhash{kArray}} ) {
if (ref($elem) == "CODE") {
%thisHash = &$elem;
}
else {
%thisHash = %$elem;
}
...
}
However ref ($elem) is always scalar or undefined. I tried func, &func, \&func, \%{&func}, in %myhash to no effect.
how do I extract the hash within the function in the main body?
Apart from the code sample you give being invalid Perl, the main problems seem to be that you are using == to compare strings instead of eq, and you are assigning a hash reference to a hash variable %thishash. I assure you that ref $elem never returns SCALAR with the data you show
It would help you enormously if you followed the common advice to use strict and use warnings at the top of your code
This will work for you
for my $elem ( #{ $myhash{kArray} } ) {
my $this_hash;
if ( ref $elem eq 'CODE' ) {
$this_hash = $elem->();
}
else {
$this_hash = $elem;
}
# Do stuff with $this_hash
}
or you could just use a map like this
use strict;
use warnings;
use 5.010;
use Data::Dump;
my %myhash = (
k1 => v1,
kArray => [
{
name => "anonymous hash",
},
\&funcThatReturnsHash,
{
name => "another anonymous hash",
}
]
);
for my $hash ( map { ref eq 'CODE' ? $_->() : $_ } #{ $myhash{kArray} } ) {
say $hash->{name};
}
sub funcThatReturnsHash {
{ name => 'a third anonymous hash' };
}
output
anonymous hash
a third anonymous hash
another anonymous hash
If you turn on strict and warnings, you'll see that:
foreach my $elem(#{mynahs{kArray}}) {
Isn't valid. You need at the very least a $ before mynahs.
But given something like this - your approach works - here's an example using map to 'run' the code references:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
sub gimme_hash {
return { 'fish' => 'paste' };
}
my $stuff =
[ { 'anon1' => 'value' },
\&gimme_hash,
{ 'anon2' => 'anothervalue' }, ];
my $newstuff = [ map { ref $_ eq "CODE" ? $_->() : $_ } #$stuff ];
print Dumper $newstuff;
Turns that hash into:
$VAR1 = [
{
'anon1' => 'value'
},
{
'fish' => 'paste'
},
{
'anon2' => 'anothervalue'
}
];
But your approach does work:
foreach my $element ( #$stuff ) {
my %myhash;
if ( ref $element eq "CODE" ) {
%myhash = %{$element -> ()};
}
else {
%myhash = %$element;
}
print Dumper \%myhash;
}
Gives:
$VAR1 = {
'anon1' => 'value'
};
$VAR1 = {
'fish' => 'paste'
};
$VAR1 = {
'anon2' => 'anothervalue'
};

Problems with sorting a hash of hashes by value in Perl

I'm rather inexperienced with hashes of hashes - so I hope someone can help a newbie...
I have the following multi-level hash:
$OCRsimilar{$ifocus}{$theWord}{"form"} = $theWord;
$OCRsimilar{$ifocus}{$theWord}{"score"} = $OCRscore;
$OCRsimilar{$ifocus}{$theWord}{"distance"} = $distance;
$OCRsimilar{$ifocus}{$theWord}{"similarity"} = $similarity;
$OCRsimilar{$ifocus}{$theWord}{"length"} = $ilength;
$OCRsimilar{$ifocus}{$theWord}{"frequency"} = $OCRHashDict{$ikey}{$theWord};
Later, I need to sort each second-level element ($theWord) according to the score value. I've tried various things, but have failed so far. The problem seems to be that the sorting introduces new empty elements in the hash that mess things up.
What I have done (for example - I'm sure this is far from ideal):
my #flat = ();
foreach my $key1 (keys { $OCRsimilar{$ifocus} }) {
push #flat, [$key1, $OCRsimilar{$ifocus}{$key1}{'score'}];
}
for my $entry (sort { $b->[1] <=> $a->[1] } #flat) {
print STDERR "#$entry[0]\t#$entry[1]\n";
}
If I check things with Data::Dumper, the hash contains for example this:
'uroadcast' => {
'HASH(0x7f9739202b08)' => {},
'broadcast' => {
'frequency' => '44',
'length' => 9,
'score' => '26.4893274374278',
'form' => 'broadcast',
'distance' => 1,
'similarity' => 1
}
}
If I don't do the sorting, the hash is fine. What's going on?
Thanks in advance for any kind of pointers...!
Just tell sort what to sort on. No other tricks are needed.
#!/usr/bin/perl
use warnings;
use strict;
my %OCRsimilar = (
focus => {
word => {
form => 'word',
score => .2,
distance => 1,
similarity => 1,
length => 4,
frequency => 22,
},
another => {
form => 'another',
score => .01,
distance => 1,
similarity => 1,
length => 7,
frequency => 3,
},
});
for my $word (sort { $OCRsimilar{focus}{$a}{score} <=> $OCRsimilar{focus}{$b}{score} }
keys %{ $OCRsimilar{focus} }
) {
print "$word: $OCRsimilar{focus}{$word}{score}\n";
}
Pointers: perlreftut, perlref, sort.
What seems suspicious to me is this construct:
foreach my $key1 (keys { $OCRsimilar{$ifocus} }) {
Try dereferencing the hash, so it becomes:
foreach my $key1 (keys %{ $OCRsimilar{$ifocus} }) {
Otherwise, you seem to be creating an anonymous hash and taking the keys of it, equivalent to this code:
foreach my $key1 (keys { $OCRsimilar{$ifocus} => undef }) {
Thus, I think $key1 would equal $OCRsimilar{$ifocus} inside the loop. Then, I think Perl will do auto-vivification when it encounters $OCRsimilar{$ifocus}{$key1}, adding the hash reference $OCRsimilar{$ifocus} as a new key to itself.
If you use warnings;, the program ought to complain Odd number of elements in anonymous hash.
Still, I don't understand why Perl doesn't do further auto-vivication and add 'score' as the key, showing something like 'HASH(0x7f9739202b08)' => { 'score' => undef }, in the Data dump.

Perl accessing the elements in a hash/hash reference data structure

I have a question I'm hoping you could help with as I am new to hashes and hash reference stuff?
I have the following data structure:
$VAR1 = {
'http://www.superuser.com/' => {
'difference' => {
'http://www.superuser.com/questions' => '10735',
'http://www.superuser.com/faq' => '13095'
},
'equal' => {
'http://www.superuser.com/ ' => '20892'
}
},
'http://www.stackoverflow.com/' => {
'difference' => {
'http://www.stackoverflow.com/faq' => '13015',
'http://www.stackoverflow.com/questions' => '10506'
},
'equal' => {
'http://www.stackoverflow.com/ ' => '33362'
}
}
If I want to access all the URLs in the key 'difference' so I can then perform some other actions on the URLs, what is the correct or preferred method of accessing those elements?
e.g I will end up with the following URLs that I can then do stuff to in a foreach loop with:
http://www.superuser.com/questions
http://www.superuser.com/faq
http://www.stackoverflow.com/faq
http://www.stackoverflow.com/questions
------EDIT------
Code to access the elements further down the data structure shown above:
my #urls;
foreach my $key1 ( keys( %{$VAR1} ) ) {
print( "$key1\n" );
foreach my $key2 ( keys( %{$VAR1->{$key1}} ) ) {
print( "\t$key2\n" );
foreach my $key3 ( keys( %{$VAR1->{$key1}{$key2}} ) ) {
print( "\t\t$key3\n" );
push #urls, keys %{$VAR1->{$key1}{$key2}{$key3}};
}
}
}
print "#urls\n";
Using the code above why do I get the following error?
Can't use string ("13238") as a HASH ref while "strict refs" in use at ....
It is not difficult, just take the second level of keys off every key in the variable:
my #urls;
for my $key (keys %$VAR1) {
push #urls, keys %{$VAR1->{$key}{'difference'}};
}
If you're struggling with dereferencing, just keep in mind that all values in a hash or array can only be a scalar value. In a multilevel hash or array the levels are just single hashes/arrays stacked on top of each other.
For example, you could do:
for my $value (values %$VAR1) {
push #urls, keys %{$value->{'difference'}};
}
Or
for my $name (keys %$VAR1) {
my $site = $VAR1->{$name};
push #urls, keys %{$site->{'difference'}};
}
..taking the route either directly over the value (a reference to a hash) or over a temporary variable, representing the value via the key. There is more to read in perldoc perldata.

Perl WWW:Mechanize Accessing data in a hash reference

I have a question I'm hoping you could help with?
This is the last part I need help with in understanding hash references
Code:
my $content_lengths; # this is at the top
foreach my $url ( # ... more stuff
# compare
if ( $mech->response->header('Content-Length') != $content_length ) {
print "$child_url: different content length: $content_length vs "
. $mech->response->header('Content-Length') . "!\n";
# store the urls that are found to have different content
# lengths to the base url only if the same url has not already been stored
$content_lengths->{$url}->{'different'}->{$child_url} = $mech->response->header('Content-Length');
} elsif ( $mech->response->header('Content-Length') == $content_length ) {
print "Content lengths are the same\n";
# store the urls that are found to have the same content length as the base
# url only if the same url has not already been stored
$content_lengths->{$url}->{'equal'}->{$child_url} = $mech->response->header('Content-Length');
}
What it looked like using Data::Dumper
$VAR1 = {
'http://www.superuser.com/' => {
'difference' => {
'http://www.superuser.com/questions' => '10735',
'http://www.superuser.com/faq' => '13095'
},
'equal' => {
'http://www.superuser.com/ ' => '20892'
}
},
'http://www.stackoverflow.com/' => {
'difference' => {
'http://www.stackoverflow.com/faq' => '13015',
'http://www.stackoverflow.com/questions' => '10506'
},
'equal' => {
'http://www.stackoverflow.com/ ' => '33362'
}
}
};
What I need help with:
I need help understanding the various ways of accessing the different parts in the hash reference and using them to do things, such as print them.
So for example how do I print all the $url from the hash reference (i.e from Data::Dumper that will be http://www.superuser.com/ and http://www.stackoverflow.com/)
and how do I print all the $child_url or a particular one/subset from $child_url and so on?
Your help with this is much appreciated,
thanks a lot
You can navigate your hashref thusly:
$hashref->{key1}{key2}{keyN};
For example, if you want the superuser equal branch:
my $urlArrayref = $hashref->{'http://www.superuser.com/'}{'equal'};
More to the point, to print the urls (first level key) of the hashref, you would do:
foreach my $key ( keys( %{$hashref} ) ) {
print( "key is '$key'\n" );
}
Then if you wanted the second level keys:
foreach my $firstLevelKey ( keys( %{$hashref} ) ) {
print( "first level key is '$firstLevelKey'\n" );
foreach my $secondLevelKey ( keys( %{$hashref->{$firstLevelKey}} ) ) {
print( "\tfirst level key is '$secondLevelKey'\n" );
}
}
And so forth...
----- EDIT -----
This is working sample code from your example above:
#!/usr/bin/perl
use strict;
use warnings;
my $content_lengths = {
'http://www.superuser.com/' => {
'difference' => {
'http://www.superuser.com/questions' => '10735',
'http://www.superuser.com/faq' => '13095'
},
'equal' => {
'http://www.superuser.com/ ' => '20892'
}
},
'http://www.stackoverflow.com/' => {
'difference' => {
'http://www.stackoverflow.com/faq' => '13015',
'http://www.stackoverflow.com/questions' => '10506'
},
'equal' => {
'http://www.stackoverflow.com/ ' => '33362'
}
}
};
foreach my $key1 ( keys( %{$content_lengths} ) ) {
print( "$key1\n" );
foreach my $key2 ( keys( %{$content_lengths->{$key1}} ) ) {
print( "\t$key2\n" );
foreach my $key3 ( keys( %{$content_lengths->{$key1}{$key2}} ) ) {
print( "\t\t$key3\n" );
}
}
}
Which results in this output:
http://www.superuser.com/
difference
http://www.superuser.com/questions
http://www.superuser.com/faq
equal
http://www.superuser.com/
http://www.stackoverflow.com/
difference
http://www.stackoverflow.com/faq
http://www.stackoverflow.com/questions
equal
http://www.stackoverflow.com/