perlでリストをユニークにする
perlでリストをユニークにする方法です。
perlには配列などをユニークにするメソッドがありません。
なので自分でなんとかして処理するしかありません。
方法1
簡単な方法はリストをハッシュのキーに詰めていき、
最後にハッシュのキーをリストとして取得する方法。
uniq.pl
my @list = qw|a b a b c a d|; print "list : @list \n"; my %temp; for (@list) { $temp{$_} = 1; } my @result = keys %temp; print "result: @result \n";
実行するとユニークになっています。
が、ハッシュのキーは順番が保障されないため、
入力のリストと順番が合っていません。
# perl uniq.pl
list : a b a b c a d
result: c a b d
方法2
ハッシュを配列スライスすれば同じことがループせずにできます。
uniq2.pl
my @list = qw|a b a b c a d|; print "list : @list \n"; my %temp; @temp{@list} = 1; my @result = keys %temp; print "result: @result \n";
実行するとユニークになっています。
が、同様に順番は保障されません。
# perl uniq2.pl
list : a b a b c a d
result: c a b d
方法3
簡単で順番も保障されて、そこそこ性能がいい方法がこちら。
uniq3.pl
my @list = qw|a b a b c a d|; print "list : @list \n"; my %temp; my @result = grep !$temp{$_}++, @list; print "result: @result \n";
結果はユニークになっていて、順番も保障されます。
# perl uniq3.pl
list : a b a b c a d
result: a b c d
メソッドにしておいても便利です。
sub uniq { my ($class, @array) = @_; my %appearance; my @unique = grep !$appearance{$_}++, @array; return @unique; }
どういう処理になっているかというと、
listの一番目のaが処理されるとき、
$temp{a}はundefとなります。
undefはfalseとなるので、!でtrueとして判断されます。
@resultの格納対象となります。
その後、++でインクリメントされますが、
undefをインクリメントすると1となります。
2番目のbが処理されるときも、同様の判定が行われ、
@resultの格納対象になります。
つぎに3番目のa(2回目)が来たとき。
$temp{a}は1番目のaで処理されているので値は1になります。
1はtrueなので、それが!でfalseになり、
@resultの格納対象外になります。
その後、++でインクリメントされて2になります。
つまり、同じ値が2回以上来た場合は
常にfalseとなり、@resultの格納対象外となります。
こちらからは以上です