ファイルの各行の重複を削除します


7

たとえば、各行の重複を削除するにはどうすればよいですか?

1 1 1 2 1 2 3
5 5 4 1 2 3 3

この出力を取得したい:

1 2 3 
5 4 1 2 3

多くの行(100,000)があり、各行には一意の値が必要です。Perlは最速かもしれませんが、PerlまたはBashでそれを行うにはどうすればよいですか?

回答:


12

awkを使用するオプションは次のとおりです。

awk '{ while(++i<=NF) printf (!a[$i]++) ? $i FS : ""; i=split("",a); print ""}' infile > outfile

編集、コメント付きで更新:

  1. while (++i<=NF)

    $ 0がawkの完全な行であるため、whileループを初期化し、「i」をプリクリメントします。

    したがって、$ 1(最初のフィールド)から始まります。行を最後までループします(「フィールド数」のawkに組み込まれている「NF」以下)。デフォルトのフィールドセパレータはスペースです。デフォルトのセパレータは簡単に変更できます。

  2. printf (!a[$i]++) ? $i FS : ""

    これは三項操作です。

    したがって、入力が配列!a[$i]++にない場合は$ iを出力し、入力されている場合は ""を出力します。(この方法が気に入らない場合は!、削除して元に戻すことができ$i FS : ""ます)。

  3. i=split("",a)

    通常、それはNULLスプリットです。この場合、次の行のIがリセットされます。

  4. print ""

    出力の行を終了します(実際には100%の理由ではありません)。そうしないと、次の出力が得られます。

    1 2 3 5 4 1 2 3 の代わりに
    1 2 3
    5 4 1 2 3


5
現在および将来の読者を支援するために、回答をある程度文書化してみてください。これはコンパクトで効率的ですがawk、テストと操作の順序、三項演算子、split("",a)配列をリセットする癖(およびリセットの戻り値i)および特殊変数NFand に依存しているため、あまり慣れていない人にはまったく読めませんFS。そのような説明は答えをさらに良くします!
ダニエルアンダーソン

@DanielAndersson怠けていることに対する謝罪、更新。ありがとう!
オタクウォーラー

1
nerdwaller:あなたが1 2 3 4 5 1 2 3 W / Oステップ4を取得する理由は...で投げていない\ / nは、これまでwのすべての出力は、printfのを介して行われていることである
ティンク

ステップ2は、現在の番号のインデックスで配列値をインクリメントするため機能します。このインデックスが空の場合、テストはを返し!false、比較後に増分が行われます。ループが次に同じ番号を見つける!trueと、インデックスに対応する値が前回値に設定されていたため、比較が返されます。フィールドは再びインクリメントされますが、この「合計カウント」は後で使用されません(ただし、問題はありません)。
ダニエルアンダーソン

ステップ3ではa、次の行の繰り返しのために配列が削除されます。split("",a)は、配列を削除するための速記ですa(注意については、ドキュメントを参照してください)。副作用として、この操作もを返します0。次の反復にi設定する必要がある0ため、split()呼び出しは個別のi=0呼び出しの代わりに割り当てに代わりに使用され、一部の文字が保存されます(おそらく読みやすくなります)。
ダニエルアンダーソン

5

以来ruby、私の知っているすべてのLinuxディストリビューションが付属しています:

ruby -e 'STDIN.readlines.each { |l| l.split(" ").uniq.each { |e| print "#{e} " }; print "\n" }' < test

ここに、test要素を含むファイルがあります。

このコマンドの機能を説明するには、Rubyは左から右にほとんど読み込めますが、

  • 入力を読み取ります(< testシェルから取得します)
  • 入力の各行を通過します
  • 項目を区切る1つのスペースに基づいて行を配列に分割します(split(" ")
  • この配列から一意の要素を取得します(順序どおり)
  • 一意の要素ごとに、スペースを含めて印刷します(print "#{e} "
  • 独自の要素を使い終わったら、改行を印刷します

2

純粋なbashではありませんが、...:

while read line; do
    printf "%s\n" $line | sort -u | tr '\n' ' '
    echo ''
done < file

行は副産物としてソートされます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.