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

Hi all,

I have a quick, simple question....

If you want to know how many elements are in an array, you can set a scalar = to an array, i.e. $scalar = @array.

If you want to know the number of pairs in a hash, you can use keys (%hash).

What is going on when you set a scalar = a hash? The output is in the form of A / B where A and B are both integers. I am having trouble finding documentation on this.

Thanks in advance,

Cameron

Replies are listed 'Best First'.
Re: setting a scalar = to a hash?
by tinita (Parson) on Oct 13, 2004 at 16:58 UTC
    see perldata

    perldoc perldata If you evaluate a hash in scalar context, it returns false if the hash is empty. If there are any key/value pairs, it returns true; more precisely, the value returned is a string consisting of the number of used buckets and the number of allocated buckets, separated by a slash. This is pretty much useful only to find out whether Perl's internal hashing algorithm is performing poorly on your data set. For example, you stick 10,000 things in a hash, but evaluating %HASH in scalar context reveals "1/16", which means only one out of sixteen buckets has been touched, and presumably contains all 10,000 of your items. This isn't supposed to happen.
Re: setting a scalar = to a hash?
by davido (Cardinal) on Oct 13, 2004 at 16:58 UTC

    Using keys in scalar context returns the number of elements in the hash.

    my $size = keys %hash;

    This is a very inexpensive operation (efficient); there is no list created when you evaluate keys in scalar context. So the way you've found to do it is the correct solution.

    Update:
    A hashing algorithm works by allocating a series of 'buckets' into which elements are plopped. The number of buckets is large enough to distribute the elements in such a way (hopefully) that lookups can be very quick. Usually this means a few items in each bucket. There's a really good discussion on this topic in Mastering Algorithms with Perl, published by O'Reilly & Associates.


    Dave

Hashes Explained
by ikegami (Patriarch) on Oct 13, 2004 at 17:37 UTC

    I don't know about perl's implementation specifically, so I'm just explaining the general concept.

    An associative array (such as a Perl hash) is implemented as an array. To figure out into in which element of the array -- called buckets -- a key belongs, a function is applied to the key. The function always returns the same number for a given key, but the number is not unique among all keys. In other words, a hashing algorithm is applied to the key.

    For example, given a hash of 8 buckets, the hasing function could return
    3 for key "foo"
    4 for key "bar"
    3 for key "bla"

    The structure would look like:

    @hash_guts = ( undef, undef, undef, [ $bla_node, $foo_node ], [ $bar_node ], undef, undef, );

    Where a node contains the key and the value:

    bless([$key, $val], Node)

    To find $hash{"foo"}, "foo" is passed through the hashing algorithm. Then, the list in the appropriate bucket is scanned for the appropriate key. Once the node with the right key is found, the value is returned.

    In the above example, scalar(%hash) would return "2/8". (2 buckets out of 8 are holding 3 entries.) So what does that mean? Contemplate searching for node7 in these two hashes:

    @hash1_guts = ( # scalar(%hash1) is 2/8 undef, [ $node1 ], undef, undef, undef, undef, [ $node2, $node3, $node4, $node5, $node6, $node7 ], undef, ); @hash2_guts = ( # scalar(%hash2) is 6/8 [ $node1 ], [ $node2 ], [ $node3 ], [ $node4, $node5 ], [ $node6 ], undef, undef, [ $node7 ], );

    The second hash would return a result much more quickly because it doesn't have to search through a long list after finding the right bucket. The closer the numerator of scalar(%hash) is to the numbers of keys, the less time the average lookup will take.

    Now consider adding another element to the second hash. It's almost guaranteed to make a list longer, so more buckets are added for future growth:

    @hash2_guts = ( # scalar(%hash2) is now 7/16 [ $node1 ], undef, [ $node2 ], undef, [ $node3 ], undef, [ $node4, $node5 ], undef, [ $node6 ], undef, undef, undef, undef, [ $node8 ], [ $node7 ], undef, );
Re: setting a scalar = to a hash?
by dragonchild (Archbishop) on Oct 13, 2004 at 16:58 UTC
    You're getting the number of hash-buckets filled over the number of hash-buckets total. It's a completely useless value unless you plan on doing some really heavy debugging. In other words, it's not very useful.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      It's a completely useless value
      Not completely useless :-) It can be used in a boolean context to determine whether the hash is empty.

      Dave.

        That's because hashes will return 0 if they're empty. It's special-cased. :-)

        Being right, does not endow the right to be rude; politeness costs nothing.
        Being unknowing, is not the same as being stupid.
        Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
        Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: setting a scalar = to a hash?
by doowah2004 (Monk) on Oct 13, 2004 at 20:13 UTC
    Thank you tinita and dragonchild, I set up tests to try to draw out the meaning, but could not find the pattern....

    Cameron


    Update: Now thank you everyone, there is such wealth of information here on the boards, that I am never sorry that I ask a question, even one a simple as this...
Re: setting a scalar = to a hash?
by jdporter (Paladin) on Oct 14, 2004 at 15:58 UTC