Monthly Archives: August 2012

Fastest way to check for an empty hash in Perl?

Recently motivated out of curiosity, I and a coworker were benchmarking different approaches to determining if a hash is empty in Perl. Expanding on this a little I present these curious results. In summary, it seems that there are roughly two code paths we’re hitting here. One for if (scalar %hash) and if (%hash), and another for if (keys %hash), if (values %hash), if (scalar keys %hash), and if (scalar values %hash). The latter is much faster when you hit a non-empty hash. It feels somewhat unfortunate that the simplest approach is (approximately) slowest.

hash size: 0
                      Rate if_scalar  if if_values if_keys if_scalar_values if_scalar_keys
if_scalar        3125000/s        -- -3%      -21%    -23%             -24%           -24%
if               3205128/s        3%  --      -19%    -21%             -22%           -22%
if_values        3937008/s       26% 23%        --     -2%              -4%            -5%
if_keys          4032258/s       29% 26%        2%      --              -2%            -2%
if_scalar_values 4098361/s       31% 28%        4%      2%               --            -1%
if_scalar_keys   4132231/s       32% 29%        5%      2%               1%             --
hash size: 3
                      Rate if_scalar   if if_keys if_scalar_keys if_values if_scalar_values
if_scalar         967118/s        --  -1%    -86%           -87%      -87%             -88%
if                978474/s        1%   --    -86%           -86%      -87%             -88%
if_keys          7142857/s      639% 630%      --            -1%       -7%             -10%
if_scalar_keys   7246377/s      649% 641%      1%             --       -6%              -9%
if_values        7692308/s      695% 686%      8%             6%        --              -3%
if_scalar_values 7936508/s      721% 711%     11%            10%        3%               --
hash size: 500
                      Rate   if if_scalar if_scalar_values if_values if_scalar_keys if_keys
if                912409/s   --       -2%             -88%      -88%           -88%    -88%
if_scalar         927644/s   2%        --             -87%      -88%           -88%    -88%
if_scalar_values 7352941/s 706%      693%               --       -1%            -4%     -4%
if_values        7462687/s 718%      704%               1%        --            -3%     -3%
if_scalar_keys   7692308/s 743%      729%               5%        3%             --     -0%
if_keys          7692308/s 743%      729%               5%        3%             0%      --

From the script:

#!/usr/bin/env perl

use strict;
use warnings;
use Benchmark qw(cmpthese);

my %hash_empty = ();
my %hash_small = (1..6);
my %hash_large = (1..1000);

foreach my $ref (\%hash_empty, \%hash_small, \%hash_large) {
  print 'hash size: ' . scalar(keys(%$ref)) . "\n";
  cmpthese(5_000_000, {
    if => sub { if (%$ref) { 1 } else { 0 } },
    if_scalar => sub { if (scalar %$ref) { 1 } else { 0 } },
    if_keys => sub { if (keys %$ref) { 1 } else { 0 } },
    if_values => sub { if (values %$ref) { 1 } else { 0 } },
    if_scalar_keys => sub { if (scalar keys %$ref) { 1 } else { 0 } },
    if_scalar_keys => sub { if (scalar keys %$ref) { 1 } else { 0 } },
    if_scalar_values => sub { if (scalar values %$ref) { 1 } else { 0 } },
  });
}