Perl get value of a key - perl

I have been stuck in trying to create an array of keys (example_com,example_ca ..etc) if they are set to 1, I have tried using for loop and foreach loop, but keep getting ARRAY# error.
$VAR1 = [
{
'example_com' => '1',
'example_ca' => '1'
}
];
Thanks

This will be because you have an array containing a hash. The array is one element long.
So you 'get' to the hash, by dereferencing element zero.
Thus:
my $hash_ref = $VAR1->[0];
print join "\n", keys %{$hash_ref},"\n";
foreach my $key ( keys %{$VAR1->[0]} ) {
print "$key => $VAR1->[0]{$key}\n";
}

Exactly for you source data:
my #array_of_keys = ();
for( keys %{ $VAR1->[0] } ) {
push #array_of_keys, $_ if $VAR1->[0]{ $_ } eq '1';
}
print "Keys with 1: #array_of_keys";

An expanded example of how to get an array of keys if you have multiple hashes in your container array:
my $VAR1 = [
{
'example_com' => '1',
'example_ca' => '1',
'not_set' => '0'
},
{
'EXAMPLE_com' => '1',
'EXAMPLE_ca' => '1',
'NOT_SET' => '0',
}
];
my #arrayOfHashes = #{$VAR1};
foreach my $array (#arrayOfHashes)
{
my #onlyOnes;
my #arrayOfKeys = sort keys %{$array};
foreach my $key (#arrayOfKeys)
{
next if ($array->{$key} ne 1);
push #onlyOnes, $key;
}
print "\nKey names:\n";
foreach my $key (#onlyOnes)
{
print "$key\n";
}
}
output:
Key names:
example_ca
example_com
Key names:
EXAMPLE_ca
EXAMPLE_com

Related

I can't print keys and values in Perl

I have a data structure that I got from this code.
my $name = $data->{Instances}->[0]->{Tags};
That data structure looks like this
$VAR1 = [
{
'Key' => 'Name',
'Value' => 'fl-demo'
},
{
'Value' => 'FL',
'Key' => 'state'
}
];
I'm trying to print the keys and values with this
foreach my $key (sort keys %$name) {
my $value = $name->{$key};
print "$key => $value\n";
}
I'm getting
Not a HASH reference at ./x.pl line 19.
The tags are returned as an array, not a hash. So you're looking at doing something like this, instead, to iterate over them:
foreach my $tag (#$name) {
my $key = $tag->{Key};
my $val = $tag->{Value};
print "$key => $val\n";
}
The data structure dump of variable $name indicates that you have array reference.
You can use loop to output the data of interest, do not forget to dereference $name variable.
use strict;
use warnings;
use feature 'say';
my $name = [
{
'Key' => 'Name',
'Value' => 'fl-demo'
},
{
'Value' => 'FL',
'Key' => 'state'
}
];
say "$_->{Key} = $_->{Value}" for #$name;
Output
Name = fl-demo
state = FL
Elaborating on a previous answer:
$name is a reference to an array containing references to hashes.
#$name and #{$name} (equivalent representations) refer to the array that $name references.
${$name}[0] and $name->[0] (equivalent representations) refer to the first hash in the array referenced by $name.
${$name}[0]{'Key'}, $name->[0]->{'Key'}, etc. (equivalent representations) refer to 'Key''s hash value in the first hash in the array referenced by $name.
As such, the following would iterate over all array and hash elements:
foreach my $hashref ( #{$name} )
{
foreach my $key ( sort(keys(%{$hashref})) )
{
printf("%s => %s\n",$key,$hashref->{$key});
}
print "\n";
}
Or, more compactly (and arguably unreadably):
printf("%s\n",join("\n", map {
my $h = $_;
join(', ', map { sprintf('%s=%s',$_,$h->{$_}) } sort(keys(%{$h})) );
} #{$name} ));

Iterate through values of a HASH and convert to comma separated strings

I want to iterate through the values of a big hash, and if any of the values of that hash are keys, I want to convert it into a comma separated list which can be parsed in 'query_form'.
Right now from the data below I have:
name=Bob&surname=Whitbread&customerErrors=HASH(Xa456) (for example)
Here's what I have so far:
sub convertArgsToQueryString {
my $class = shift;
my $args = shift;
return unless ($args && ref($args) eq 'HASH');
foreach my $key (values %$args) {
if (ref($key) eq 'HASH') {
# change to a comma separated list
}
}
my $dummyURL = URI->new('', 'http');
$dummyURL->query_form(%$args);
return $dummyURL->query;
}
Data:
my $data = {
'name' => 'Bob',
'surname' => 'Whitbread',
'customerErrors' => {
'error1' => 'paymentError',
'error2' => 'addressError'
},
};
Query Form:
name=Bob&surname=Whitbread&customerErrors=paymentError,addressError
This will do what you want
print join ",", values %{$data->{customerErrors}},"\n";
Although I would suggest, rather than error1 as hash keys, you'd be better off with an array:
my $data = {
'name' => 'Bob',
'surname' => 'Whitbread',
'customerErrors' => [ 'paymentError', 'addressError' ],
};
Scaling that out to be generic, you will find the ref function to be helpful:
foreach my $key ( keys %$data ) {
print "$key is a ", ref $data->{$key},"\n";
if ( ref $data->{$key} eq 'HASH' ) {
print join ",", values %{$data->{$key}};
}
else {
print $data -> {$key},"\n";
}
}
Or tersely:
print join "\&", map { #join iterated on &
join "=", $_, #join paired values on =
ref $data->{$_} eq 'HASH' #ternary to check reference type
? values %{ $data->{$_} } #extract values if HASH
: $data->{$_} #extract just value if not.
} keys %$data; #iterate keys of data
Which gives as output:
name=Bob&customerErrors=addressError=paymentError&surname=Whitbread

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');
}
}

Get value from hash of hashes

I would like to get value from hash of hashes but i do not. My code is :
sub test {
my $filename = $_[0];
open INFILE, ${filename} or die $!;
my %hashCount;
my #firstline = split('\t',<INFILE>);
shift(#firstline);
while (my $line = <INFILE>)
{
my %temp;
chomp($line);
my #line = split('\t', $line);
foreach my $cpt (1..$#line) {
$temp{$firstline[$cpt-1]}=$line[$cpt];
}
$hashCount{$line[0]}={%temp};
}
return %hashCount;
}
sub get_hash_of_hash {
my $h = shift;
foreach my $key (keys %$h) {
if( ref $h->{$key}) {
get_hash_of_hash( $h->{$key} );
}
else {
say $h->{$key};
}
}
}
And when i display my hash :
$VAR10679 = 'M00967_43_1106_2493_14707';
$VAR10680 = {
'A' => '1',
'B' => '0',
'C' => '1',
'D' => '0',
'E' => '0'
};
My first function return my hash of hashes and i get my specific value with the second function.
So I want to get value like that :
my %hashTest = test("FILE.txt");
get_hash_of_hash(%hashTest,"M00967_43_1106_2493_14707","A")
//return value '1'
You can either access nested elements like
$hash{keyA}{keyB}
or we can write a function that walks the data structure, like
sub walk {
my ($hashref, #keys) = #_;
my $pointer = $hashref;
for my $key (#keys) {
if (exists $pointer->{$key}) {
$pointer = $pointer->{$key};
} else {
die "No value at ", join "->", #keys;
}
}
return $pointer;
}
which can be used like
my %hash = (
'M00967_43_1106_2493_14707' => {
'A' => '1',
'B' => '0',
'C' => '1',
'D' => '0',
'E' => '0'
},
);
say walk(\%hash, 'M00967_43_1106_2493_14707', 'A');
Note: When using Data::Dumper, pass references to the Dump function:
print Dump \%hash; # not print Dump %hash
This is neccessary to show the correct data structure.
Your hash holds references to hashes.
You can access them like this:
$hashTest{'M00967_43_1106_2493_14707'}{'A'};
See perlref for more info
Use this subroutine..
sub get_hash_of_hash {
my $h = shift;
foreach my $key (keys %$h) {
if( ref $h->{$key}) {
get_hash_of_hash( $h->{$key} );
}
else {
print $h->{$key};
}
}
}

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.