« 東京凰籃学院の教材 | トップページ | 白子川源流を訪ねて »

2014年10月15日 (水)

Perl: 順序を変えずに配列の重複を取り除く

自作のブラウザに以前と同じブックマークを追加してしまった場合など、順番は保持しつつあとから加えたものだけを削除したいことがある・・・かもしれない。

一番原始的なのは、元の配列@aの中身を順番を明示しつつハッシュに格納する方法。

noSortCut.cgi

#! /usr/bin/perl

$|=1;

my @a = ('いちご','みかん','りんご','ぶどう','ざくろ','みかん','いちご','ざくろ','みかん','いちご');
my @b;

print "Content-type:text/plain\n\n";

print "\@a: ";
foreach(@a){print "$_ ";}
print "\n";
print "\#↑ はじめの配列\n";
print "\n";

my %c;

my $i = 0;
foreach(@a){
    print "$_\($i\)";
    if($c{$_} eq ''){ # if(!$c{$_}) だと0が入っていても $c{'a'}=0 がfalse判定されてしまうからダメ
        $c{$_} = $i;
        ++$i;
    }
}

print "\n";
print "\#↑ \$iが5以上のときは既に\%cが埋まっているので数字は格納されない\n";
print "\n";

foreach(keys %c){
    print "\$c\{\'$_\'\}=$c{$_} ";
    $b[$c{$_}] = $_;
}

print "\n";
print "\#↑ \%cには各のキーに対し,4以下の番号のみが格納されているが順番が崩れている\n";
print "\n";

print "\@b: ";
foreach(@b){print "$_ ";}
print "\n";
print "\#↑ 出来上がり";
print "\n\n";

exit;

出力

@a: いちご みかん りんご ぶどう ざくろ みかん いちご ざくろ みかん いちご 
#↑ はじめの配列

いちご(0)みかん(1)りんご(2)ぶどう(3)ざくろ(4)みかん(5)いちご(5)ざくろ(5)みかん(5)いちご(5)
#↑ $iが5以上のときは既に%cが埋まっているので数字は格納されない

$c{'りんご'}=2 $c{'みかん'}=1 $c{'いちご'}=0 $c{'ざくろ'}=4 $c{'ぶどう'}=3 
#↑ %cには各のキーに対し,4以下の番号のみが格納されているが順番が崩れている

@b: いちご みかん りんご ぶどう ざくろ 
#↑ 出来上がり

上のように、ハッシュは順番を保持しないことがわかる。

次にスカラー変数で処理してみる。各要素を一つの文字列にしてしまえば順番は保持されるはずだ。

noSortCut2.cgi

#! /usr/bin/perl

$|=1;

my @a = ('いちご','みかん','りんご','ぶどう','ざくろ','みかん','いちご','ばなな','ざくろ','みかん','いちご');
my @b;

print "Content-type:text/plain\n\n";

print "\@a: ";
foreach(@a){print "$_ ";}
print "\n\#↑ はじめの配列\n\n";

my $s = "\@";
foreach(@a){
    if($s !~ /\@$_\@/){$s .= "$_\@";}
}

print "\$s: $s\n\n";

$s =~ s/^\@|\@$//g;

@b = split("\@", $s);

print "\@b: ";
foreach(@b){print "$_ ";}
print "\n\#↑ 出来上がり\n\n";

exit;

出力

@a: いちご みかん りんご ぶどう ざくろ みかん いちご ばなな ざくろ みかん いちご 
#↑ はじめの配列

$s: @いちご@みかん@りんご@ぶどう@ざくろ@ばなな@

@b: いちご みかん りんご ぶどう ざくろ ばなな 
#↑ 出来上がり

しかしデータに区切り文字と同じものが含まれていると使えない。上の例ではメールアドレスなど。やはり配列のままがいいようだ。最初の例を簡単にしてみる。

noSortCut3.cgi

#! /usr/bin/perl

$|=1;

my @a = ('いちご','みかん','りんご','ぶどう','ざくろ','みかん','いちご','ばなな','ざくろ','みかん','いちご');
my @b;

print "Content-type:text/plain\n\n";

print "\@a: ";
foreach(@a){print "$_ ";}
print "\n\#↑ はじめの配列\n\n";

my %c;
foreach(@a){
    if(!$c{$_}){ $c{$_} = 1; push @b, $_;}
}

print "\@b: ";
foreach(@b){print "$_ ";}
print "\n\#↑ 出来上がり\n\n";

exit;

出力

@a: いちご みかん りんご ぶどう ざくろ みかん いちご ばなな ざくろ みかん いちご 
#↑ はじめの配列

@b: いちご みかん りんご ぶどう ざくろ ばなな 
#↑ 出来上がり

なんとこれをもっと簡単に記述できることがわかった。

noSortCut4.cgi

#! /usr/bin/perl

$|=1;

my @a = ('いちご','みかん','りんご','ぶどう','ざくろ','みかん','いちご','ばなな','ざくろ','みかん','いちご');
my @b;

print "Content-type:text/plain\n\n";

print "\@a: ";
foreach(@a){print "$_ ";}
print "\n\#↑ はじめの配列\n\n";

my %c;
my @b = grep {!$c{$_}++} @a;

print "\@b: ";
foreach(@b){print "$_ ";}
print "\n\#↑ 出来上がり\n\n";

exit;

出力はnoSortCut3.cgiと全く同じ。perlは奥が深いと思った。

 

 

« 東京凰籃学院の教材 | トップページ | 白子川源流を訪ねて »

2018年10月
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

ブックマーク

無料ブログはココログ