下のコードが何をしているか理解できるだろうか?

#!/opt/local/bin/perl

use strict;
use warnings;

my @name1 = qw/yuta kenta koz ichiro masato manabu aiko/;
my @name2 = qw/hiroshi motoo koz takeshi makoto manabu/;

my %union = ();
my %intersection = ();

$union{$_}++ && $intersection{$_}++ for (@name1, @name2);
my @union = keys %union;
my @intersection = keys %intersection;

2つの配列の和集合と積集合を検出して新たな配列を作っているコードだが、この場合の前提条件としてはそれぞれの配列内の要素がすべてユニーク値でなければいけないという事だ。

結果は
配列@union

['aiko','manabu','takeshi','koz','kenta','hiroshi','motoo','yuta','makoto','ichiro','masato']

配列@intersection

['koz','manabu']

となるが
例えば@name1にもう一つ"aiko"があれば@intersectionは

['koz','manabu','aiko']

となってしまう。

なので、両方の配列に存在する値を求めていたとしたら間違った配列が出来てしまう事になる。

なぜ@intersectionに"aiko"が入ってしまうのかはforeachループの中での

$union{$_}++ && $intersection{$_}++

このコードが原因なのだが、これが最初理解できなかった。

何をやっているかというとまずfor(foreach)ループに2つの配列@name1と@name2を渡している。
それぞれの要素がデフォルト変数$_に代入されるのでその値を%unionのキーとし、キーに対する値としてプラス1の数値を代入(或は上書き)している。
初回のループではまず配列@name1から要素"yuta"が$_に代入されハッシュ%unionにキーとして"yuta"が作成される。
そして$union{'yuta'}の値として1が代入される。

さらに$intersection{$_}++もここで実行されるだろうと思いきやここはパスされてしまう。
要は$union{$_}++の検証結果が偽になるから実行されない訳だがなぜ偽になってしまうのか?

これはインクリメント演算子の位置が関係あるのだがこの場合$union{$_}++の評価結果は"$union{'yuta'}に1足して成功した"という結果ではなくて"$union{'yuta'}の値"の評価の後1を足しているという事なのだ。

&&演算子は左辺が偽だと右辺は実行されない。当然最初は$union{'yuta'}には値が存在しないから偽になる。
そして次に"yuta"がきた時には$union{'yuta'}には1が入ってる。評価結果は真となり$intersection{$_}++も実行されるというという訳だ。

カテゴリ:

トラックバック(0)

トラックバックURL: http://blog.beanz-net.jp/beanz_mtos/mt-tb.cgi/6

コメントする