0

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!

Borodin
  • 126,100
  • 9
  • 70
  • 144
Lisa
  • 331
  • 1
  • 9
  • 15
  • It would have been easier if you had provided the input data too. Even better would have been a runnable demonstration of the problem. – ikegami Apr 30 '12 at 18:16
  • Apologies, the input data comes from a Mysql database originally, which is then changed in different ways to make %Normalisedfithash and %P1Tallyhash - I thought it would be confusing to explain where it came from, but I can see now that I should have provided more info – Lisa Apr 30 '12 at 18:53
  • You're right that we don't need to know where it come from. I simply meant an illustration of the input like the one you provided for the current output. – ikegami Apr 30 '12 at 18:54

2 Answers2

1

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;
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • That will leave `@$array` containing only hashes with a *false* value of the `Tally` element. That is largely the opposite of the OP's code which tried to delete all elements with a zero `Tally` element. – Borodin Apr 30 '12 at 18:22
  • @Borodin, Fixed. (Like I told the OP, it would have been better if he had provided a runnable demonstration of the problem. Then it would have been trivial to test my solution.) – ikegami Apr 30 '12 at 18:25
  • This is now leaving some of the arrays completely empty e.g '7412' => [] - how can I remove these? – Lisa Apr 30 '12 at 20:06
  • @Lisa, Do another scan, delete keys of the outer hash that have for value a reference to an empty array. Code added to answer. – ikegami May 01 '12 at 06:04
1

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;
}
Borodin
  • 126,100
  • 9
  • 70
  • 144