2010.06.17
yna 開発

連想記憶配列の結合

 最近のスクリプト言語には、ハッシュ、連想記憶配列、辞書と呼ばれる型が準備されています。PerlやRuby、Pythonといった言語では、普通の配列とは別の型として準備されていますが、PHPはちょっと珍しくて、配列をどちらでも使えるようにしてあります。

 バーコードを扱っていたときに面白い現象に遭遇したので説明します。

 まずは、Perl

%hshBarlist1 = ( "3905865021719" => "A", "3900218077276" => "A" );
%hshBarlist2 = ( "3905865021719" => "B", "3907604020069" => "B" );
%hshMerge = (%hshBarlist1, %hshBarlist2);

[実行結果]
3907604020069 => B
3905865021719 => B
3900218077276 => A

 最初のハッシュを次の次のハッシュで上書きします。順番がばらばらになってしまうのはPerlのハッシュの機能なので、仕方がないところです。

 次にRuby、(初期化と表示は面倒なので省略)

hshMerge = hshBarlist1.merge( hshBarlist2 )

[実行結果]
3907604020069 => B
3900218077276 => A
3905865021719 => B

 最初のハッシュを次の次のハッシュで上書きした新しいハッシュを返す仕様です。こちらも、順番が変わってしまいます。

 さてPHPですが、単純な書き方ができます。これは、いいですね。(初期化と表示は面倒なので省略)

$hshMerge = $hshBarlist1 + $hshBarlist2 ;

[実行結果]
3905865021719 => A
3900218077276 => A
3907604020069 => B

 配列ですから順番も変わりません。結構重宝します。
 ところが、よく見ると実行結果が他の言語とは異なっています。他の言語では、同じキー(”3905865021719″)があった場合に、左辺値(最初の値)を右辺値(次の値)で上書きしてしまうのですが、PHPではすでに値があれば、それを優先するようです。これは移植するときなど注意が必要です。
 そこで、同じような機能にarray_mergeという関数があります。これを使ってみましょう。

$hshMerge = array_merge( $hshBarlist1, $hshBarlist2 );

[実行結果]
3905865021719 => B
3900218077276 => A
3907604020069 => B

 これだと、最初の配列を次の配列で上書きします。
 しかしこれには大きな落とし穴があったのです。よくよくPHPのマニュアルを見ると添え字が数値の場合は、リナンバーされるとあります。キーに使われているのコードは、13桁のバーコードなのですが、32bitのCPU環境では整数にみなすことができませんので、文字列として扱われます。ところが64bitのCPU環境では、十分に数値の範囲のなかです。そうするとこんな結果になってしまうのです。

[実行結果]
0 => A
1 => A
2 => B
3 => B

 まあ一種の不整合な部分を使ってコードを書いていたわけです。
 PHPの配列は、連想記憶配列的な使い方ができるけど、あくまでも配列。キーには数字を使わないほうが無難です。
 他の言語からPHPに移植する人はこのあたりに注意が必要です。

 最後にコードだけですが、Pythonの記述。

hshMerge = {};
hshMerge.update( hshBarlist1 )
hshMerge.update( hshBarlist2 )


 3行にもなってしまいます。もう少し行数を減らせないかなと、参考書を読んでいましたが、間違った記述として、Rubyと同じような書き方が出ています。この例では、hshMergeにはnillが入り、hshBarlist1は、変更されてしまいます。うーん、方法はなさそうです。

hshMerge = hshBarlist1.update( hshBarlist2 )


同じようなオブジェクト指向色の強いスクリプト言語としてよく比較されるPythonとRubyですが、結構設計思想は違うみたいです。
Python:一つ一つのメソッドは単純に、複雑なことをする場合は、それなり行数をかけて記述する。
Ruby:簡潔に記述するためには、クラスの複雑性が増してもかまわない。

動作環境。
OS/Windows XP
PHP/5.3.0
Ruby/1.8.7
Perl/5.10.1
Python/2.6

一覧に戻る