What do you get if you evaluate a hash in scalar context?

前端 未结 5 2119
滥情空心
滥情空心 2020-12-03 07:20

Consider the following snippet:

use strict;
use warnings;

my %a = ( a => 1,
          b => 2,
          c => \'cucu\',
          d => undef,
            


        
相关标签:
5条回答
  • 2020-12-03 07:31

    The number of used buckets starts out to be approximately the number of keys; allocated buckets is consistently the lowest power of 2 > the number of keys. 5 keys will return 5/8. Larger numbers of unique keys grow slower, such that a hash %h that is just the list (1..128), with 64 key/value pairs, somehow gets a scalar value of 50/128.

    However, once the hash has allocated its buckets, they will remain allocated even if you shrink the hash. I just made a hash %h with 9 pairs, thus 9/16 scalar; then when I reassigned %h to have just one pair, its scalar value was 1/16.

    This actually makes sense in that it lets you test the hash's size, like a scalar of a simple array does.

    0 讨论(0)
  • 2020-12-03 07:41

    [The OP is asking about the format of the strings returned by Hash::Util's bucket_ratio() and by a hash in scalar context before Perl 5.26. Since Perl 5.26, a hash in scalar context no longer returns a string in this format, returning the number of elements in the hash instead.]

    A hash is an array of linked lists. A hashing function converts the key into a number which is used as the index of the array element ("bucket") into which to store the value. The linked list handles the case where more than one key hashes to the same index ("collision").

    The denominator of the fraction is the total number of buckets.

    The numerator of the fraction is the number of buckets which has one or more elements.

    For hashes with the same number of elements, the higher the number, the better. The one that returns 6/8 has fewer collisions than the one that returns 4/8.

    0 讨论(0)
  • 2020-12-03 07:47

    To focus too much on this fractional pattern (as an indicator for internal details of the hash), can be confusing. There is an aspect of the "scalar value" of a hash that is important for potentially every Perl program and that is, if it is considered true in Boolean context, see an example:

    if (%h) {
        print "Entries in hash:\n";
        for my $k (sort keys %h) {
            print "$k: $h{$k}\n";
        }
    }
    

    In perldoc perldata, section Scalar-values, you can read that

    [...] The Boolean context is just a special kind of scalar context where no conversion to a string or a number is ever performed.

    and, some paragraphs later,

    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 [...]

    0 讨论(0)
  • 2020-12-03 07:49

    From 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.

    In your case, you have five values (1,2,''cucu',undef, and '321312321') that have been mapped to by eight keys (a,b,c,d,r,br,cr, and dr).

    0 讨论(0)
  • 2020-12-03 07:57

    The behaviour has changed since Perl 5.25. See perldata for Perl 5.26:

    Prior to Perl 5.25 the value returned was 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.

    As of Perl 5.25 the return was changed to be the count of keys in the hash. If you need access to the old behavior you can use Hash::Util::bucket_ratio() instead.

    0 讨论(0)
提交回复
热议问题