Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Why Does the Hash Seem Empty?

by o2bwise (Scribe)
on Jul 20, 2007 at 19:06 UTC ( [id://627854]=perlquestion: print w/replies, xml ) Need Help??

o2bwise has asked for the wisdom of the Perl Monks concerning the following question:



Hi Monks,

I have this application at work where I need to produce files, but where there is no desire to do so in the event the files would be empty.

At a stage in the code, I have a hash. I check to see if the hash has at least one value. If it does, at the next portion of code, its contents are printed out to a file.

The problem is, the program produced files of zero file size. In my investigation, I found that for such an occurrence, the hash actually had one key,value pair. However, when the code proceeded to print out the contents of the hash, there was nothing printed out!

Can someone share with me why this is happening and how I can correctly identify the hash contains at least one key,value pair in such a way that I can next print out all of the contents of the hash?

Here is the code before some added test snippets.

my $count = 0; while (my($key, $value) = each(%ip_discover_count) and $count == 0) { $count++; } if ($count > 0) { my $seedFileName = "$CC\_discover.txt"; open (SEED,">$dir/$seedFileName"); while ((my $key, my $value) = each(%ip_discover_count)) { $ip = &trim($key); my $snmp_read = &trim($ip_discover_snmp{$key}); print SEED "$ip\t\$snmp_read\n"; } close (SEED); }


And here is the code with some checks, where I verified the hash had a key, value pair and whose contents did not print out in the second while loop.

my $count = 0; my $seedFileName = "$CC\_discover.txt"; open (SEED,">$dir/$seedFileName"); while (my($key, $value) = each(%ip_discover_count) and $count == 0) { print SEED "Key: $key\tValue: $value\n"; $count++; } if ($count > 0) { my $seedFileName = "$CC\_discover.txt"; #open (SEED,">$dir/$seedFileName"); print SEED "Count:\t$count\n"; while ((my $key1, my $value1) = each(%ip_discover_count)) { $ip = &trim($key1); my $snmp_read = &trim($ip_discover_snmp{$key1}); print SEED "xx$ip\xx\n"; } close (SEED); }


Thanks much for any help,

Tony

Replies are listed 'Best First'.
Re: Why Does the Hash Seem Empty?
by dave_the_m (Monsignor) on Jul 20, 2007 at 19:22 UTC
    There is only one 'each' iterator associated with a hash. You first while loop breaks off before having iterated through the whole hash, and so the second while loop continues the 'each' iteration where the previous one left off.

    To determine whether the hash has elements, just use it in a scalar context:

    if (%ip_discover_count) { ...

    Dave.

Re: Why Does the Hash Seem Empty?
by jwkrahn (Abbot) on Jul 20, 2007 at 19:31 UTC
    my $count = 0; while (my($key, $value) = each(%ip_discover_count) and $count == 0) { $count++; } if ($count > 0) { my $seedFileName = "$CC\_discover.txt"; open (SEED,">$dir/$seedFileName"); while ((my $key, my $value) = each(%ip_discover_count))

    The first each reads one key/value pair from the hash and then the next each continues where the first left off and reads the next key/value pair from the hash.

    You probably want something like this:

    if ( keys %ip_discover_count ) { my $seedFileName = "$CC\_discover.txt"; open my $SEED, '>', "$dir/$seedFileName" or die "Cannot open '$dir +/$seedFileName' $!"; while ( my ( $key, $value ) = each %ip_discover_count ) { $ip = trim( $key ); my $snmp_read = trim( $ip_discover_snmp{ $key } ); print $SEED "$ip\t\$snmp_read\n"; } close $SEED; }
      Thank you.

      A much better way of identifying that a hash is not empty.

      Why would the perl interpret a separate while loop TO CONTINUE from a previous one?

      That doesn't make sense to me at all.

      I just did your change and it worked. Thanks again as the files it produces are needed on Saturday at 3AM! :-)

      Tony
        From each:
        There is a single iterator for each hash, shared by all each, keys, and values function calls in the program; it can be reset by reading all the elements from the hash, or by evaluating keys HASH or values HASH .
        Perl isn't continuing a while loop, it is starting a new while loop, but your loop condition is the hash iterator, which was not reset.

        From perldoc -f each:

        ========================

        When the hash is entirely read, a null array is returned in list context (which when assigned pro­duces a false (0) value), and "undef" in scalar context. The next call to "each" after that will start iterating again. There is a single iterator for each hash, shared by all "each", "keys", and "values" function calls in the program; it can be reset by reading all the elements from the hash, or by evaluating "keys HASH" or "values HASH". If you add or delete elements of a hash while you're iterating over it, you may get entries skipped or duplicated, so don't.

        ========================

        So, it's a function of the way that each is designed at a lower level -- to preserve iterator locations unless keys or values is re-run, most likely a similar methodology to the way C's strtok(2) works by first specifying the target string, then being able to specify NULL for the first arg and picking up where you last left off.

Re: Why Does the Hash Seem Empty?
by FunkyMonk (Chancellor) on Jul 20, 2007 at 19:28 UTC
    My guess is that you're adding empty key/value pairs to the hash. Show us the result of your extra print statements (if there's not too much).

    What does trim() do? Could it be responsible for creating empty entries in your hash?

    Some other comments about your code:

    • You are using strict and warnings, aren't you?
    • Perl has the wonderfull keys function which allows you to replace this

      my $count = 0; while (my($key, $value) = each(%ip_discover_count) and $count == 0) { $count++; } if ($count > 0)

      with this:

      if ( keys %ip_discover_count )

    • Always check that open succeeds: open (SEED,">$dir/$seedFileName") or die $!;
    • "$CC\_discover.txt" doesn't do what you think it does. Use single quotes, or double up the backslash.

    update: keys is unnecessary, as demonstrated by dave_the_m. I was thrown by the OP's use of $count, which doesn't count.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://627854]
Approved by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (2)
As of 2024-04-24 17:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found