Delete value from Perl hash of arrays of hashes - perl

I'm trying to delete values from a hash of arrays of hashes that I created with the following code:
while ((my $Genotype1, my $Fitness1) = each (%Normalisedfithash)) {
while ((my $Parent1A, my $TallyP1) = each(%P1Tallyhash)) {
my $ParentTally = 0;
my $SecondParent = {
Parent2 => $Parent1A,
Tally => $ParentTally,
};
push #{ $StoredParentshash{$Genotype1}}, $SecondParent;
I have been trying to delete values from %StoredParentshash where Tally is zero. (I have further code which updates Tally, but some are not updated and I want them removed from the hash).
I have written the following:
for my $Parent (keys %StoredParentshash) {
my $aref1 = $StoredParentshash{$Parent};
for my $hashref1 (#$aref1) {
my $Tally = $hashref1->{'Tally'};
if ($Tally == 0){
delete $hashref1->{'Tally'};
delete $hashref1->{'Parent2'};
}
}
}
This code sort of deletes the data, but when I use Data::Dumper the structure I get back looks like this:
'7412' => [
{},
{
'Tally' => 1,
'Parent2' => '2136'
},
{},
{},
{},
How can I completely remove the keys where the Tally is zero rather than being left with {}?
Thanks!

The code that you say has generated the data structure is faulty, as it is missing two closing braces.
You must show either your actual code with balanced { .. } or a dump of %StoredParentshash before we can help you properly.
If Tally and Parent2 are the only keys in the SecondParent hashes, then you should write something like
for my $children (values %StoredParentshash) {
#$children = grep $_->{Tally} != 0, #$children;
}

Your data looks like:
my %StoredParentshash = (
key1 => [
{
Tally => ...,
...
},
...
],
...
);
And you want to delete some of the array elements. Generally, I use grep for that.
#array = grep keep_condition(), #array;
Here is no exception.
for my $array (values(%StoredParentshash)) {
#$array = grep $_->{Tally}, #$array;
}
And to delete any arrays that are now empty:
for my $key (keys(%StoredParentshash)) {
delete $StoredParentshash{$key} if !#{ $StoredParentshash{$key} };
}
Or combined:
for my $key (keys(%StoredParentshash)) {
my $array = $StoredParentshash{$key};
#$array = grep $_->{Tally}, #$array;
delete $StoredParentshash{$key} if !#$array;
}

Related

How to group hash of numbers that are equals

I'm kinda new to programming and Perl... I would say I could do that in C like language, but I've got no idea how to do that in Perl.
To simplify things...
my $sql = [
{ ID => 1 },
{ ID => 2 },
{ ID => 2 },
{ ID => 2 },
{ ID => 3 }
];
my $number = 0;
foreach( #{ $sql } ) {
my #array = ();
if ( $number != $_->{ ID } ) {
push #array, $number;
if( $number ) {
push #array, '(' . $_->{ ID } . ')'; #how should I cycle that ?
}
}
$number = $_->{ ID };
print("#array");
}
I somehow need to get an output like this 1(2)(2)(2)3. I don't want to work with real code here, so I made a simple example how I use it now. I would be really grateful for help.
This code gives me 01 (2)2 (3) which is wrong. I've been thinking about it about for multiple hours so my results are getting worse and worse because I'm stuck and looping through the same mistakes.
Welcome to Perl and programming in general.
One straightforward way to do this is to count the number of times each value appears. If only once then print it without parentheses. If more than once then print it with parentheses and repeat according to the count for that value. I'm using the 'x' operator to repeat a string. '*' x 3 would give you '***' for example.
use strict;
use warnings;
my $sql = [
{ ID => 1 },
{ ID => 2 },
{ ID => 2 },
{ ID => 2 },
{ ID => 3 }
];
my $number = 0;
my %count_values;
foreach( #{ $sql } ) {
# make the number the key, count how many times it appears.
$count_values{$_->{ID}}++;
}
my $output_string = '';
foreach my $key_number ( sort {$a<=>$b} keys %count_values ){
# if just one occurance then don't add parentheses.
if ($count_values{$key_number} == 1){
$output_string .= $key_number;
} else {
$output_string .= "($key_number)" x $count_values{$key_number};
}
}
print $output_string;

Printing Hash of Hash into a Matrix Table in Perl

I have a data structure like this:
#!/usr/bin/perl -w
my $hash = {
'abTcells' => {
'mesenteric_lymph_node' => {
'Itm2a' => '664.661',
'Gm16452' => '18.1425',
'Sergef' => '142.8205'
},
'spleen' => {
'Itm2a' => '58.07155',
'Dhx9' => '815.2795',
'Ssu72' => '292.889'
}
}
};
What I want to do is to print it out into this format:
mesenteric_lymph_node spleen
Itm2a 664.661 58.07155
Gm16452 18.1425 NA
Sergef 142.8205 NA
Dhx9 NA 815.2795
Ssu72 NA 292.889
What's the way to do it.
I'm currently stuck with the following code https://eval.in/44207
foreach my $ct (keys %{$hash}) {
print "$ct\n\n";
my %hash2 = %{$hash->{$ct}};
foreach my $ts (keys %hash2) {
print "$ts\n";
my %hash3 = %{$hash2{$ts}};
foreach my $gn (keys %hash3) {
print "$gn $hash3{$gn}\n";
}
}
}
Use Text::Table for output. Beautify to taste.
#!/usr/bin/env perl
use strict;
use warnings;
use Text::Table;
my $hash = {
'abTcells' => {
'mesenteric_lymph_node' => {
'Itm2a' => '664.661',
'Gm16452' => '18.1425',
'Sergef' => '142.8205'
},
'spleen' => {
'Itm2a' => '58.07155',
'Dhx9' => '815.2795',
'Ssu72' => '292.889'
}
}
};
my $struct = $hash->{abTcells};
my #cols = sort keys %{ $struct };
my #rows = sort keys %{ { map {
my $x = $_;
map { $_ => undef }
keys %{ $struct->{$x} }
} #cols } };
my $tb = Text::Table->new('', #cols);
for my $r (#rows) {
$tb->add($r, map $struct->{$_}{$r} // 'NA', #cols);
}
print $tb;
Output:
mesenteric_lymph_node spleen
Dhx9 NA 815.2795
Gm16452 18.1425 NA
Itm2a 664.661 58.07155
Sergef 142.8205 NA
Ssu72 NA 292.889
Now, the order of the rows above is different than the one you show because I wanted it to be consistent. If you know the set of all possible rows, then you can specify another order obviously.
First thing would be to separate out the two hashes:
my %lymph_node = %{ $hash->{abTcells}->{mesenteric_lymph_node} };
my %spleen = %{ $hash->{abTcells}->{spleen} };
Now, you have two separate hashes that contains the data you want.
What we need is a list of all the keys. Let's make a third hash that contains your keys.
my %keys;
map { $keys{$_} = 1; } keys %lymph_node, keys %spleen;
Now, we can go through all your keys and print the value for each of the two hashes. If one of the hashes doesn't have the data, we'll set it to NA:
for my $value ( sort keys %keys ) {
my $spleen_value;
my $lymph_nodes_value;
$spleen_value = exists $spleen{$value} ? $spleen{$value} : "NA";
$lymph_node_value = exists $lymph_node{$value} ? $lymph_node{$value} : "NA";
printf "%-20.20s %-9.5f %-9.5f\n", $key, $lymph_node_value, $spleen_value;
}
The printf statement is a nice way to tabularize data. You'll have to create the headings yourself. The ... ? ... : ... statement is an abbreviated if/then/else If the statement before the ? is true, then the value is the value between the ? and the :. Else, the value is the value after the :.
Both of your inner hashes have the same keys, So do a foreach on one of the hashes to get the key, and then print both.

how to declare array reference in hash refrence

my $memType = [];
my $portOp = [];
my $fo = "aster.out.DRAMA.READ.gz";
if($fo =~/aster.out\.(.*)\.(.*)\.gz/){
push (#{$memType},$1);
push (#{$portOp},$2);
}
print Dumper #{$memType};
foreach my $mem (keys %{$portCapability->{#{$memType}}}){
//How to use the array ref memType inside a hash//
print "entered here\n";
//cannot post the rest of the code for obvious reasons//
}
I am not able to enter the foreach loop . Can anyone help me fix it?
Sorry this is not the complete code . Please help me.
%{$portCapability->{#{$memType}}}
This doesn't do what you may think it means.
You treat $portCapability->{#{$memType}} as a hash reference.
The #{$memType} is evaluated in scalar context, thus giving the size of the array.
I aren't quite sure what you want, but would
%{ $portCapability->{ $memType->[0] } }
work?
If, however, you want to slice the elements in $portCapability, you would need somethink like
#{ $portCapability }{ #$memType }
This evaluates to a list of hashrefs. You can then loop over the hashrefs, and loop over the keys in an inner loop:
for my $hash (#{ $portCapability }{ #$memType }) {
for my $key (keys %$hash) {
...;
}
}
If you want a flat list of all keys of the inner hashes, but don't need the hashes themselves, you could shorten above code to
for my $key (map {keys %$_} #{ $portCapability }{ #$memType }) {
...;
}
I think what you want is this:
my $foo = {
asdf => {
a => 1, b => 2,
},
foo => {
c => 3, d => 4
},
bar => {
e => 5, f => 6
}
};
my #keys = qw( asdf foo );
foreach my $k ( map { keys %{ $foo->{$_} } } #keys ) {
say $k;
}
But you do not know which of these $k belongs to which key of $foo now.
There's no direct way to get the keys of multiple things at the same time. It doesn't matter if these things are hashrefs that are stored within the same hashref under different keys, or if they are seperate variables. What you have to do is build that list yourself, by looking at each of the things in turn. That's simply done with above map statement.
First, look at all the keys in $foo. Then for each of these, return the keys inside that element.
my $memType = [];
my $portOp = [];
my $fo = “aster.out.DRAMA.READ.gz”;
if ($fo =~ /aster.out\.(\w+)\.(\w+)\.gz/ ) { #This regular expression is safer
push (#$memType, $1);
push (#$portOp, $2);
}
print Dumper “#$memType”; #should print “DRAMA”
#Now if you have earlier in your program the hash %portCapability, your code can be:
foreach $mem (#$memType) {
print $portCapability{$mem};
}
#or if you have the hash $portCapability = {…}, your code can be:
foreach $mem (#$memType) {
print $portCapability->{$mem};
}
#Hope it helps

Iterating over a complex data structure

I have what appears to be a hash of a hash of an array of hashes. I'm trying to pull some values out and I'm stumped (this is way deeper than I would go with a structure. It looks like this.....
%htest = (
8569 => {
4587 => [
{
date=> "2011-01-15",
approved=> 1,
},
{
date=> "2011-01-12",
approved=> 1,
},
],
1254 => [
{
date=> "2011-01-12",
approved=> "",
},
{
date=> "",
approved=> 1,
},
],
},
);
Trying to iterate over this thing is giving me a massive headache. I'm trying to access the number of elements under the second hash value (4587 and 1254). The number of those elements where approved="1" and the number of elements where the date contains a value.
If I could iterate over them I sure I could shove what I need into a less complex structure but so far I'm at a loss.
I got this far...
while (my ($id, $surveyhash) = each %{ $htest{'8569'} } ){
print "$enumid = $subhash\n";
print Dumper $subhash."\n";
}
That gives me the "4587" and "1254" but trying to do a dumper on $subhash just gives me....
4587 = ARRAY(0x9a9ffb0)
$VAR1 = 'ARRAY(0x9a9ffb0)
';
1254 = ARRAY(0x9a91788)
$VAR1 = 'ARRAY(0x9a91788)
';
Any idea how to iterate over this monstrosity?
Janie
Your structure has typos, you need commas between the innermost hashes and a parenthesis at the end (rather than a curly bracket)
Once you fix it you can use something like this:
my $approved = 0, my $date_has_value = 0;
while ( my ($k,$vref) = each %htest ) {
while ( my ($k,$v) = each %$vref ) {
# Now you're inside the inner hash, so there will be 2 iterations
# with $k 4587 and 1254
foreach my $item (#$v) {
# Now each $item is a reference to the innermost hashes
$approved++ if $item->{approved} == 1;
$date_has_value++ if $item->{date};
}
}
}
Here's a fairly explicit iteration that should help get you started
my ($num_approved, $num_date) = (0, 0);
# outer hash
while (my ($ka, $va) = each %htest)
{
# inner hash
while (my ($kb, $vb) = each %{$va})
{
# each hash inside the array
foreach my $h (#{$vb})
{
$num_approved += ${$h}{"approved"} == 1;
$num_date += length(${$h}{"date"}) > 0;
}
}
}
Counting match cases can be done with "scalar grep".
my ($approved, $date_has_value) = (0, 0);
for my $v1 (values %htest) {
for my $v2 (values %$v1) {
$approved += scalar grep { $$_{approved} eq '1' } #$v2;
$date_has_value += scalar grep { $$_{date} ne '' } #$v2;
}
}

How to loop json results in Perl

I am trying to output JSON from a perl script that accesses a mysql database.
How I can I loop through my query returns and turn that into JSON using the JSON module?
When I do this all I get is 1 return
while($query_handle->fetch()) {
$jsonStructure->{event};
$jsonStructure->{event}->{evid} = $evid;
$jsonStructure->{event}->{component} = $component;
$jsonStructure->{event}->{firstTime} = $firstTime;
$jsonStructure->{event}->{lastTime} = $lastTime;
$jsonStructure->{event}->{count} = $count;
$jsonStructure->{event}->{summary} = $summary;
$jsonStructure->{event}->{severity} = $severity;
}
Basically I have many events and don't know how to say event[0]...
Thank You
I think what you're looking for is this:
push #{ $jsonStructure->{events} }, {
evid => $evid,
component => $component,
...,
};
although even that is probably overkill, because you can probably do something like:
while (my $row = $dbh->fetchrow_hashref) {
push #{ $jsonStructure->{events} }, $row;
}
if all of the column names in the DB are the same as the field names you want in the JSON, and you want all columns, or:
my #keys = qw(evid component firstTime ...);
while (my $row = $dbh->fetchrow_hashref) {
my %hash;
#hash{#keys} = #$row{#keys};
push #{ $jsonStructure->{events} }, \%hash;
}
if you only want some columns, or:
# DB colname => JSON field name
my %mapping = (
event_id => 'evid',
component => 'component',
first_time => 'firstTime',
...,
);
while (my $row = $dbh->fetchrow_hashref) {
my %hash;
#hash{ values %mapping } = #$row{ keys %mapping };
push #{ $jsonStructure->{events} }, \%hash;
}
for a completely arbitrary mapping. Power of Perl and all that. :)