配列の配列 vs. 連想配列

Perlで、ある対となる二つの値を単に保存しておきたいと思った時、配列の配列を作るのと連想配列(ハッシュ)を作るのではどっちが効率がいいだろう、とふと思ったので、ベンチマークしてみた。

予想では、ハッシュ化する処理があるから、連想配列の方が遅いだろうとは思っていたのだけれど。

ベンチマークのソースは以下。仕事でIPアドレスに関係するものを作っていたので、それっぽいものにしてありますが。

#!/usr/bin/perl
use strict;
use Benchmark;

my @alpha = ( ('a'..'z'), '.');
my @ipaddr = ();
my @hostname = ();
foreach my $c ( 0..10 ) {
  foreach my $d ( 0..255 ) {
    push @ipaddr, join( '.', '192.168', $c, $d );
    push @hostname, join('', map { $alpha[int(rand(@alpha))] } (0..12) );
  }
}

timethese( 500, {
  'array' => sub {
    my $cnt = 0;
    my @array = map { [ $_, $hostname[$cnt++] ] } @ipaddr;
  },
  'hash'  => sub {
    my $cnt = 0;
    my %hash  = map { $_ => $hostname[$cnt++] } @ipaddr;
  },
} );

で、結果は以下。

Benchmark: timing 500 iterations of array, hash...
     array: 10 wallclock secs ( 9.53 usr +  0.03 sys =  9.56 CPU) @ 52.30/s (n=500)
      hash: 11 wallclock secs (10.99 usr +  0.04 sys = 11.03 CPU) @ 45.33/s (n=500)

10%ほど差が出るようですね。もっと差が出ると思ったのですけどね。

後でピンポイントに参照するのでなければ、「配列の配列」の方が効率がいいようです。

まぁ、当たり前か・・・。

#以下、追記。

ちなみに参照する方は、

#!/usr/bin/perl
use strict;
use Benchmark;

my @alpha = ( ('a'..'z'), '.');
my @array = ();
my %hash = ();

foreach my $c ( 0..10 ) {
  foreach my $d ( 0..255 ) {
    my $ipaddr = join( '.', '192.168', $c, $d );
    my $hostname = join('', map { $alpha[int(rand(@alpha))] } (0..12) );
    push @array, [ $ipaddr, $hostname ];
    $hash{$ipaddr} = $hostname;
  }
}

timethese( 1000, {
  'array' => sub {
    foreach( @array ) {
      my $key = $_->[0];
      my $val = $_->[1];
    }
  },
  'hash'  => sub {
    while( my( $key, $val ) = each %hash ) {
    }
  },
} );
Benchmark: timing 1000 iterations of array, hash...
     array:  7 wallclock secs ( 6.50 usr +  0.02 sys =  6.52 CPU) @ 153.37/s (n=1000)
      hash:  7 wallclock secs ( 7.34 usr +  0.02 sys =  7.36 CPU) @ 135.87/s (n=1000)

ホンの少しですが、やはり連想配列の方が遅いようですね。