سؤال

I'm dealing with a hash of hashes in Perl and I'm running into some problems. After a while that my code is running, it generates a hash of hashes that looks like something similar to this:

my %book = (
    +1 => {
        27 => 100,
        24 => 1000,
    },
    -1 => {
        30 => 200,
        31 => 500,
    }
);

After processing some more data, the code ends up removing two entries of the hash by using the following line of code:

delete $book{-1}{30};
delete $book{-1}{31};

Hence, the hash should be half empty. However, when later on in my code I run the following if statement:

if ((defined $book{+1}) && (defined $book{-1})){
    do A
}else{
    do B
}

my code ends up doing "thing A" rather than "thing B" which he should do since the "-1" side of the hash has been deleted. How is this possible? And, most importantly, how to solve this problem?

هل كانت مفيدة؟

المحلول

After you delete the two entries inside %{$books{-1}}, the hash reference $books{-1} still exists even though it's empty.

use strict;
use warnings;

my %book = (
    +1 => {
        27 => 100,
        24 => 1000,
    },
    -1 => {
        30 => 200,
        31 => 500,
    }
);

delete $book{-1}{30};
delete $book{-1}{31};

use Data::Dump;
dd \%book;

Outputs:

{ -1 => {}, 1 => { 24 => 1000, 27 => 100 } }

If you'd like to trim that entry, you'll have to code explicit logic for that

# Trim Hash
my @empty_keys = grep {!%{$book{$_}}} keys %book;
delete $book{$_} for @empty_keys;

Update

As ysth suggested, one alternative solution would be to test if any of the hash keys were empty instead:

if (! grep {!$book{$_} || !%{$book{$_}}} qw(1 -1)) {
    print "A\n";
} else {
    print "B\n";
}

نصائح أخرى

Rather than removing superfluous hash elements, I would prefer to make the code that used %book resilient to empty hashes, which isn't so hard to do in general

I would also be very wary of using a hash with numeric keys, because there are many strings that could represent the same number. For instance, although '1' == '1.0' is true, '1' eq '1.0' is false, and if the values were used as hash keys they would refer to different elements

With those provisos, I would write the following

I am sorry that I have only a tablet to work on at present, and the IDE doesn't allow me to copy the output text to paste here. But it is tested and working

use strict;
use warnings;

my %book = (
  +1 => {
    27 => 100,
    24 => 1000,
  },
  -1 => {
    30 => 200,
    31 => 500,
  }
);

# $book{-1} becomes an empty hash
delete $book{-1}{30};
delete $book{-1}{31};

# remove elements that have no content
for (keys %book) {
  delete $book{$_} unless keys %{ $book{$_} };
}

use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper \%book;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top