FC2ブログ
perlで、配列内の重複するデータを取り除く方法。

perlだから、きっとそういうことをしてくれる関数があるはず、と思っていたが。。。ない。
検索して、ようやく見つけたのがコレ。
#!/usr/bin/perl
use strict;
use warnings;

my @array = ('aaa', 'bbb', 'ccc', 'aaa');

my %count;
@array = grep {!$count{$_}++} @array;

foreach my $element (@array) {
  print "$element\n";
}
結果は、
aaa
bbb
ccc


へぇ~、そっかぁ~。とは、なりません!!
これがわかるくらいなら、自分で思いつくはず。

わからないのが、grepと$_。

grep

grepは簡単に調べられた。
「第一引数の条件を満たす値を第二引数の配列から取り出す」関数。
 #!/usr/bin/perl
use strict;
use warnings;

my @array = ('bash', 'csh', 'perl');

@array = grep {/sh$/} @array; # 'sh'で終わる値を取り出す。

foreach my $element (@array) {
  print "$element\n";
}
結果は、
bash
csh


$_

こういうのって、調べるのがタイヘン。
どうにか調べてみると、「 変数を省略した時に, 利用されるデフォルト変数」と書いてある。
そっかぁ、デフォルト変数ね。とは、なりません!!
よくある例は、こんな感じ。
#!/usr/bin/perl
use strict;
use warnings;

my @array = ('a', 'b', 'c');

foreach (@array) {
  print;
  print "\n";
}
結果は、
a
b
c


じゃあ、ここでは$_に何がはいるの?
@array = grep {!$count{$_}++} @array;
みんなそう思うハズ。私だけ?

気にせず、どんどん進むと、やっぱり予想するのは、配列の要素だよね。
試しに、
#!/usr/bin/perl
use strict;
use warnings;

my @array = ('aaa', 'bbb', 'ccc', 'aaa');

my %count;
@array = grep {!$count{$_}++} @array;

print "$count{aaa}\n";
print "$count{bbb}\n";
print "$count{ccc}\n";
結果は、
2
1
1


予想通り。
じゃあ、最初のスクリプトを解析してみよう
もう一度、掲載すると以下のとおり。
#!/usr/bin/perl
use strict;
use warnings;

my @array = ('aaa', 'bbb', 'ccc', 'aaa');

my %count;
@array = grep {!$count{$_}++} @array;

foreach my $element (@array) {
  print "$element\n";
}

  1. $_にaaaが代入される。
  2. $count{aaa}の値は、0。つまり、偽。
  3. よって、!$count{aaa}は真になる。
  4. !$count{$_}++なので、!$count{aaa}が評価された後に、$count{aaa}に1加えられれ、1になる。
  5. @arrayに追加される。
  6. bbb, cccも同様に@arrayh追加される。
  7. $_にaaaが代入される。
  8. $count{aaa}の値は、1。つまり、真。
  9. よって、!$count{aaa}は偽になる。
  10. !$count{$_}++なので、!$count{aaa}が評価された後に、$count{aaa}に1加えられ、2になる。

よって、重複した値は取り除かれる。
いやぁ、こんな2行で重複を取り除けるなんて、素晴らしい。

参考
【Perl Tips】 Perl で、配列中の重複レコードを削除するには?
スポンサーサイト





テーマ:プログラミング
ジャンル:コンピュータ
コメント
コメントを投稿
URL:
Comment:
Pass:
秘密: 管理者にだけ表示を許可
 
トラックバック
この記事へのトラックバック