Perl Sort Perl hash of hash like structure by values - perl

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";
}

Related

How to get data from Perl data structure

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"
}

try to print mixed hash element in perl

I try to print hash key and value in tree form. my perl code is given below.
use strict ;
use warnings ;
my %hash = (
first => {
a => "one",
b => "two",
c => "three",
},
second => {
d => "four",
e => "five",
f => "six",
},
third => "word",
);
foreach my $line (keys %hash) {
print "$line: \n";
foreach my $elem (keys %{$hash{$line}}) {
print " $elem: " . $hash{$line}->{$elem} . "\n";
}
}
output error message:
second:
d: four
f: six
e: five
third:
Can't use string ("word") as a HASH ref while "strict refs" in use at C:\Users\Dell\Music\PerlPrac\pracHash\hshofhsh_net.pl line 19.
here, under third key value not print. how can i do it?
You can't dereference a string ($hash{third}, i.e. word). You can test whether a particular scalar is a reference or not using ref:
for my $line (keys %hash) {
print "$line: \n";
if ('HASH' eq ref $hash{$line}) {
for my $elem (keys %{ $hash{$line} }) {
print " $elem: $hash{$line}{$elem}\n";
}
} else {
print " $hash{$line}\n";
}
}

How to dereference only hash of hash of array in Perl?

{
'A' => ['B'], //hash of array
'C' => {'D' => [ 'E']} //hash of hash of array
}
When try to parse hash of hash of array. getting "Not a HASH reference" error. Even I tried used exists and defined keywords to avoid this error. But result is same error.
From above i need to only iterate hash of hash of array.
foreach my $keys (keys %$hash){
print "$keys";
if (defined $hash->{$keys}->{maptype}){
foreach my $array_element ( #{$hash->{$keys}->{'D'}} ) {
print "$array_element");
}
}
}
Not sure if this is best practice, but:
my $hash = { A => ['B'], C => {D => ['E'], F => [qw(G H I)]}, J=>42 };
for my $key (keys %$hash) {
if (ref $hash->{$key} eq 'HASH') {
for my $subkey (keys %{$hash->{$key}}) {
say "$key => $subkey => [", join(",", #{$hash->{$key}{$subkey}}), "]";
}
}
}
outputs
C => D => [E]
C => F => [G,H,I]

Print the value in Hash of Hash for two different keys in Perl

Below is a hash in Perl:
my %hash = (
'episode1' => {
'when' => '08.13.97',
'airdate' => '08.13.97',
'episodenumber' => '101',
'id' => '103511',
'title' => 'Cartman Gets an Anal Probe',
'available' => 'true'
},
'episode2' => {
'when' => '08.20.97',
'airdate' => '08.20.97',
'episodenumber' => '102',
'id' => '1035156',
'title' => 'Weight Gain 4000',
'available' => 'true'
}
);
I want to print the "id" of both episodes,but the below code is not working:
foreach my $key1 ( keys %hash ) {
foreach my $key2 ( keys %{$hash{$key1}} ) {
print "$hash{$key1}{$key2}{id}\n";
}
}
Please help.
The problem is that you're trying to print something that doesn't exist: There is no value that matches $hash{$key1}{$key2}{id}.
Try this code, which prints out the value in the hash of hashes that has the key "id":
use strict;
use warnings;
for my $episode (keys %hash){
print "$hash{$episode}{id}\n";
}
103511
1035156
Try using map:
my #ids = map { $hash{$_}{"id"} } sort keys %hash;
Or if you still need the results as a hash:
my %ids_by_key = map { ($_, $hash{$_}{"id"}) } keys %hash;
Try this:
foreach my $key1 ( keys %hash ) {
print "$hash{$key1}{id}\n";
}
or
foreach my $key1 ( keys %hash ) {
foreach my $key2 ( keys %{$hash{$key1}} ) {
print "$hash{$key1}{$key2}\n" if($key2 eq 'id');
}
}

not able to access hash of hash of array values

I have written the following code in Perl. The code is reading a pdb file and getting some values. Ignore the top part of the code,where everything is working perfect.
Problem is in the sub-routine part, where I try to store arrays in the hash3 with model as key another key position
the array values can be accessed inside the if condition using this :
$hash3{$model}{$coordinates}[1].
but when I go out of all foreach loop and try to access the elements I only get one value.
Please look at the end foreach loop and tell me is it the wrong way to access the hash values.
The pdb file I am using can be downloaded from this link http://www.rcsb.org/pdb/download/downloadFile.do?fileFormat=pdb&compression=NO&structureId=1NZS
#!/usr/bin/perl
open(IN,$ARGV[0]);
my #phosphosites;
my $model=1;
my %hash3;
while(<IN>)
{
#findmod(#line);
#finddist;
#findfreq;
if((/^MODRES/) && (/PHOSPHO/))
{
#line=split;
push(#phosphosites, $line[2]);
#print "$line[4]";
}
foreach $elements (#phosphosites){
if(/^HETATM\s+\d+\s+CA\s+$i/)
{
#line1=split;
#print "$line1[5]";
#print "$line1[6] $line1[7] $line1[8]\n";
push(#phosphositesnum, $line1[5]);
}
}
$pos=$line1[5];
#findspatial(\#line,\#line1);
}
my #ori_data=removeDuplicates(#phosphositesnum);
sub removeDuplicates {
my %seen = ();
my #vals = ();
foreach my $i (#_) {
unless ($seen{$i}) {
push #vals, $i;
$seen{$i} = 1;
}
}
return #vals;
}
$a=(#phosphosites);
print "$a\n";
print "#phosphosites\n";
print "#ori_data\n";
close(IN);
open(IN1,$ARGV[0]);
my (#data)=<IN1>;
spatial(\#ori_data);
sub spatial {
my #spatial_array1=#{$_[0]};
foreach $coordinates(#spatial_array1)
{
$model=1;
{foreach $data1(#data){
if($data1=~ m/^HETATM\s+\d+\s+CA\s+[A-Z]*\s+[A-Z]*\s+$coordinates/)
{
#cordivals=split(/\s+/,$data1);
push #{ $sphash{$model} },[$cordivals[6], $cordivals[7], $cordivals[8]];
$hash3{$model}{$coordinates}= \#cordivals;
#print "$model $coordinates $hash3{$model}{$coordinates}[6] $hash3{$model}{$coordinates}[7] $hash3{$model}{$coordinates}[8]\n";
#print "$model $sphash{$model}[$i][0] $sphash{$model}[$i][1] $sphash{$model}[$i][2]\n";
}
elsif($data1=~ m/^ENDMDL/)
{
$model++;
}
#print "$model $coordinates $hash3{$model}{$coordinates}[6] $hash3{$model}{$coordinates}[7] $hash3{$model}{$coordinates}[8]\n";
}
}
}
#foreach $z1 (sort keys %hash3)
# {
# foreach $z2(#spatial_array1){
# print "$z1 $z2";
# print "$hash3{$z1}{$z2}[6]\n";
# print "$z2\n";
# }
# }
}
After using the Data::Dumper option it is giving me this kind of output
$VAR1 = {
'11' => {
'334' => [
'HETATM',
'115',
'CA',
'SEP',
'A',
'343',
'-0.201',
'-2.884',
'1.022',
'1.00',
'99.99',
'C'
],
'342' => $VAR1->{'11'}{'334'},
'338' => $VAR1->{'11'}{'334'},
'335' => $VAR1->{'11'}{'334'},
'340' => $VAR1->{'11'}{'334'},
'343' => $VAR1->{'11'}{'334'},
'336' => $VAR1->{'11'}{'334'}
},
'7' => {
'334' => $VAR1->{'11'}{'334'},
'342' => $VAR1->{'11'}{'334'},
'338' => $VAR1->{'11'}{'334'},
'335' => $VAR1->{'11'}{'334'},
'340' => $VAR1->{'11'}{'334'},
'343' => $VAR1->{'11'}{'334'},
'336' => $VAR1->{'11'}{'334'}
},
'2' => {
'334' => $VAR1->{'11'}{'334'},
'342' => $VAR1->{'11'}{'334'},
...
Change:
#cordivals=split(/\s+/,$data1);
to:
my #cordivals=split(/\s+/,$data1);
What seems to be happening is that all the hash elements contain references to the same array variable, because you're not making the variable local to that iteration.
In general, you should use my with all variables.