challenge ファイル内の重複行削除(後優先)

アレイのuniq」の応用編です。

入力されたテキストデータから重複する行をとりのぞいて、その結果を標準出力へ出力するプログラムを作成してください。

重複行の排除については、以下の仕様を満たしてください。

  1. 読み込み順序は変更しないこと
  2. 重複する行があった場合、以前のデータを削除すること (後に読み込んだ方が強い)
  3. ファイル全体を一度にメモリに読み込んで処理しないこと
  4. 比較は行全体で行うこと

#4.はおまけですがある/なしで作りが変わってくると思われるので追加しました。


この問題はraynstardさんにご投稿いただきました。ご協力ありがとうございます。 ところで、素朴な実装のしかたをするとメモリ容量の数倍のサイズのすべての行が異なっているファイルを読ませたときに大変なことが起こりそうな気がしますが、そういうシビアなお題設定ではないので素朴に解いてしまって構いません。シビアなのは続編にしたいと思います。

Posted feedbacks - Perl

1.入力文字をキーにして値を配列の位置を記憶。
2.存在してたらその位置にある配列の文字を空白にしておく。
3.ループ抜けたら空白を無視して出力。

※ちなみに改行コードも含めてキーとなるので、空白行が入力されてもその行はちゃんと空白行として出力されます。
1
2
3
$c=0;
while(<>){$b{$_}ne''?$r[$b{$_}]='':0;$b{$_}=$c++;push@r,$_}
print grep{$_}@r;

Perlで書いてみた。
 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
32
33
34
my $file_name = $ARGV[0];

open IN , '<' , $file_name or die "Can't open $file_name";
open CMP, '<' , $file_name or die "Can't open $file_name";

my $hash = {};
my $index= {};

for (my $n=0; my $line = <IN>; $n++ )
{
    next if (exists $hash->{$n});

    my @array = ();
    for ( my $i=0; my $cmp = <CMP> ; $i++ )
    {
        if ( $line eq $cmp )
        {
            $hash->{$i} = undef ;
            push @array , $i;
        }
    }
    seek CMP , 0 , 0 ;

    my $tmp = (sort {$b <=> $a} ( @array ))[0];
    $index->{$tmp} = undef ;
}

for (my $i=0; my $line = <CMP>; $i++)
{
    print $line if (exists $index->{$i});
}

close IN ;
close CMP;

ども、raynstardです。
ネタばらすと元ネタは.bash_historyの内容整理で
ええ。イレギュラーなんて考えていませんでした(笑

実際には部分一致での比較にしているのでもう一手間かかっていますが
こんな感じでつかっています。

大きなファイルきたらどうなるんだろうちょっと怖い作りかも
# 入力ファイルはもちろん「|」で手抜き^^;
1
perl -ne '$h{$_}=++$i; END { print "$_" foreach ( sort { $h{$a} <=> $h{$b};} keys(%h));}'

続・ファイル内の重複行削除よりも制限が緩いので、これで充分かと。

Dan the One-Liner Monger

1
'print reverse do{grep {1>$s{$_}++} reverse <>}' ~/.bash_history

Index

Feed

Other

Link

Pathtraq

loading...