kopug memo

名古屋で働くとあるWebエンジニアの覚書。

Catalystのソースを見ていたら二項演算子スライスを使ってハッシュの初期化をしていた

Catalyst::Dispatcherを見ていたら二項演算子(Multiplicative Operators)スライスを使ったハッシュの初期化をみつけた。

    @{ $self->registered_dispatch_types }{@classes} = (1) x @classes;

で、これを分かりやすく変えると下記のようになります。

    use Data::Dumper;
    
    my @keys = qw( a b c );
    my %hash;
    @hash{ @keys } = (1) x @keys;

    print Dumper \%hash;
$VAR1 = {
          'c' => 1,
          'a' => 1,
          'b' => 1
        };

要は配列をハッシュのキーにして、値は1だよと。
良く判定系の処理をするときに、配列をぐるぐる回して一致するか?とかやりたくないので、
一度ハッシュに突っ込んでから、ハッシュに存在するか?というチェックをするので、
array2hashはやるのですが、二項演算子スライスを使ってるのは初めて見た。

自分はいつもmapを使ってた。

    my %hash = map { $_ => 1 } @keys;

で、恒例のベンチマーク対決。今回はfor文もいれておいた。

#! /usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Benchmark;

my @keys = ('a'..'z', 'A'..'Z');

timethese(
            10_000,
            {
                OPERATOR     => \&operator     ,
                MAP_LOOP     => \&map_loop     ,
                FOR_LOOP     => \&for_loop     ,
            }
         );

sub operator {
    my %hash;
    @hash{ @keys } = (1) x @keys;
}

sub map_loop {
    my %hash = map { $_ => 1 } @keys;
}

sub for_loop {
    my %hash;
    for ( @keys ) {
        $hash{$_} = 1;
    }
}


結果はこの通り。

Benchmark: timing 10000 iterations of FOR_LOOP, MAP_LOOP, OPERATOR...
  FOR_LOOP:  0 wallclock secs ( 0.29 usr +  0.00 sys =  0.29 CPU) @ 34482.76/s (n=10000)
            (warning: too few iterations for a reliable count)
  MAP_LOOP:  1 wallclock secs ( 0.44 usr +  0.00 sys =  0.44 CPU) @ 22727.27/s (n=10000)
  OPERATOR:  0 wallclock secs ( 0.24 usr +  0.00 sys =  0.24 CPU) @ 41666.67/s (n=10000)
            (warning: too few iterations for a reliable count)


すいません。1番遅い方法で今までやってました。orz

追記:二項演算子 -> スライスに直しました。