私の巨大な(最大2 GiB)テキストファイルには、その中のすべての行の約100の正確な複製が含まれています(私の場合、ファイルがそうであるため、役に立たない) CSVのようなデータテーブル)。
必要なのは、元のシーケンスの順序を維持しながら(できれば、パフォーマンスを大幅に向上させるために犠牲にすることができます)、すべての繰り返しを削除することです。結果として、各行は一意になります。 100の等しい行があった場合(通常、重複はファイル全体に広がり、隣接するものではありません)、残っているのは1つだけです。
Scalaでプログラムを作成しました(考えてみてください)。これを実装するために、Scalaについて知らない場合はJava)。しかし、これをより速く実行できる、より高速なCで記述されたネイティブツールがあるのではないでしょうか?
更新:awk "!seen[$0]++" filename
ソリューションは、ファイルがあれば問題なく機能しているように見えました。 2 GiB以下でしたが、8 GiBファイルをクリーンアップしようとすると、動作しなくなります。4GiBRAMを搭載したMacと4GiBRAMを搭載した64ビットWindows7PCでは無限大になるようです。 6 GiBスワップはメモリ不足になります。この経験から、4 GiBRAMを搭載したLinuxで試してみることに熱心ではありません。
コメント
回答
#bash(Freenode)で見られるawk
ソリューション:
awk "!seen[$0]++" filename
コメント
- 2Gファイルでこれを試したところ、ノートブックで3分かかりました。悪くない。私もuniqファイル名を試しました| awk ‘!seen [$ 0] ++ ‘ですが、’ではありませんでしたより高速です。
- @HashWizard:このコマンドは並べ替えられませんが、同じ行が次に出現するたびに削除されます
- このコマンドがどのように機能するのか疑問に思っていますか? -こちらをご覧ください: unix.stackexchange.com/questions/159695/how-does-awk-a0-work
- @MaxWilliams yes 、ランダムに分散されていれば機能します。
- 改行またはスペースのある行を保持します
awk '/^\s*?$/||!seen[$0]++'
回答
sort
。ほとんどの実装では、巨大なファイルに対して特定の最適化が行われます(優れた外部ソートアルゴリズム)。この方法の利点は、特別な目的のユーティリティ内のすべての行のみをループし、インタプリタ言語内ではループしないことです。
<input nl -b a -s : | # number the lines sort -t : -k 2 -u | # sort and uniquify ignoring the line numbers sort -t : -k 1n | # sort according to the line numbers cut -d : -f 2- >output # remove the line numbers
すべての行が空白以外の文字の場合、いくつかのオプションを省略できます。
<input nl | sort -k 2 -u | sort -k 1n | cut -f 2- >output
大量の複製の場合、1つのコピーを保存するだけでよい方法メモリ内の各行のパフォーマンスが向上します。解釈のオーバーヘッドがありますが、「そのための非常に簡潔なawkスクリプトがあります(すでに enzotibによって投稿されています):
<input awk "!seen[$0]++"
簡潔さ:!seen[$0] {print} {seen[$0] += 1}
つまり、現在の行がまだ表示されていない場合は印刷してから、seen
この行のカウンター(初期化されていない変数または配列要素の数値は0)。
長い行の場合、各行のスプーフィング不可能なチェックサム(暗号化ダイジェストなど)のみを保持することでメモリを節約できます。 。たとえば、SHA-1を使用すると、必要なのは20バイトと1行あたりの一定のオーバーヘッドだけです。しかし、ダイジェストの計算はかなり遅いです。この方法は、高速のCPU(特に、ダイジェストを計算するためのハードウェアアクセラレータを備えたもの)があり、ファイルのサイズに比べてメモリが多くなく、行が十分に長い場合にのみ勝ちます。各行のチェックサムを計算できる基本的なユーティリティはありません。 Perl / Python / Ruby /…の解釈のオーバーヘッドを負担するか、専用のコンパイル済みプログラムを作成する必要があります。
<input perl -MDigest::MD5 -ne "$seen{Digest::MD5::md5($_)}++ or print" >output
コメント
- @Gilles
awk '!seen[$0]++'
の説明に基づくと、awkが2つの重複行を検出した場合、常に最初の行を保持し、すべてを無視することを意味しますか?後続のもの?(または最後のものを保持しますか?) - @ user779159最初のものを保持します:各入力行はすぐに出力されるか(最初の出現)、まったく印刷されない(繰り返し出現)。
- しかし、それはsort -uとどのように比較されますか…?
- @HashWizardプレーンな
sort -u
は順序を変更します。私の答えは、順序(正確には最初の出現の順序)を保持するソリューションを示しています。 - @Gillesは、50%重複する大きなファイル(10G)のsort-uよりも高速だと思います。 ?
回答
sort -u big-csv-file.csv > duplicates-removed.csv
出力ファイルは
コメント
- 他の回答の
awk
コマンドほど速くはありませんが、概念的には簡単です! - @Johannこれは、数十万(さらには数百万)の短い改行で終了する文字列を含むファイルで頻繁に実行しています。私が行っている実験では、かなり迅速に結果が得られます。何度も実行されるスクリプトで使用する場合は、さらに重要になる可能性があります。時間の節約はかなりのものになる可能性があります。
-
sort -u
を使用して、並べ替え中に重複を削除します。後ではなく。 (そしてメモリ帯域幅を節約します)それを別のプログラムにパイプします)。これは、出力を並べ替える場合にのみ、awk
バージョンよりも優れています。 (この質問のOPは、元の注文を保存することを望んでいるため、これは少し異なるユースケースに適した回答です。) - 私にとっては、1分ほどかかります。 550万行のファイル(合計1.8 GB)。素晴らしい。
回答
重複排除されたファイルと同じ量をメモリに保持できると仮定します(データが実際に100倍、つまり約20MiB +オーバーヘッドで複製されている場合は、Perlを使用してこれを非常に簡単に行うことができます。
$ perl -ne "print unless $dup{$_}++;" input_file > output_file
これ順序も保持されます。
必要に応じて、追加の無料ボーナスとして、%dup
ハッシュから各行の出現回数を抽出できます。
awk
を好む場合は、これも行う必要があります(perlバージョンと同じロジック、同じ順序、dup
変数):
$ awk "{if (++dup[$0] == 1) print $0;}" input_file > output_file
コメント
- これは良すぎる@ Mat、Iファイルを丸呑みしようとしていました、笑;-)
- @ManAtWorkがsedとawkの魔法の力を待っています:-)
- awkのヒントが再び素晴らしいです:- )
- perlスクリプトを変更して削除のみにすることはできますか隣接する行を複製しますか?
- @dumbledad:
uniq
それをすべて単独で行います
回答
インプレースサポートを提供する他の回答はないため、次の1つを示します。
gawk -i inplace "!a[$0]++" file
コメント
- これは順序を保持しますか?ちなみに、これは私にはうまくいきませんでした。私のバージョンは次のとおりです:
GNU Awk 4.0.2
- @Leonidはい、そうです。一意の行の最初の出現を出力します。インプレースサポートは、2013年にリリースされたバージョン4.1で最初に導入されました。
- これが答えになるはずです。 ‘は、既存または現在のファイル内の重複した文字列を実際に削除します。ここでの上位の回答とほとんどの回答は、一意の/重複した文字列のみを出力し、何もせずに作成する必要があります。結果を保存するための別の出力。
回答
uniq
http://www.computerhope.com/unix/uuniq.htm
uniq
ファイル内の繰り返し行をレポートまたはフィルターで除外します。
コメント
- 回答する場合は、なぜあなたの答えがなのかについての説明が1つです。では、この回答は以前の回答のいくつかとどのように異なりますか?
- uniqのマニュアルページから:注:
'uniq' does not detect repeated lines unless they are adjacent.
したがって、最初に並べ替えて緩める必要があります。重複しない行の順序。
回答
Python Oneライナー:
python -c "import sys; lines = sys.stdin.readlines(); print "".join(sorted(set(lines)))" < InputFile
コメント
- これにより、ファイル全体がメモリに丸呑みされ、OP ‘の問題に適さない場合があります。また、順序を維持する保証はありません
- 提案をありがとう、私は’ Pythonを学んでいます。学習目的でこれを試しました。:)
- ここ’ s は、ワンライナーではありませんが(簡潔に)Python2.7バージョンです。ファイル全体をメモリにロードしたり、印刷するためにフィードする単一の巨大な文字列を作成したりせずに、順序を維持した一意の行を返します
- @ 1_CRに感謝します今日何かを学びました:)
OrderedDict
回答
ここでの回答はどれも私のMacではうまくいかなかったので、簡単なPythonを作成しました私のために働くスクリプト。先頭/末尾の空白を無視しており、メモリ消費も気にしません。
import sys inputfile = sys.argv[1] outputfile = sys.argv[2] with open(inputfile) as f: content = f.readlines() content = [x.strip() for x in content] my_list = list(set(content)) with open(outputfile, "w") as output: for item in my_list: output.write("%s\n" % item)
上記を一意に保存します。pyして、次のように実行します:
python unique.py inputfile.txt outputfile.txt
回答
元のシーケンス順序を維持しないソリューション
次のコードピースで実行しました。
sort duplicates.txt | uniq > noDuplicates.txt
sort
コマンドは行をアルファベット順に並べ替え、uniq
コマンドは重複を削除します。
注: 最初に行を並べ替えたのは、uniq
は、隣接していない限り重複行を検出しません。
コメント
入力順序を維持せずに、uniq
にパイプするよりも効率的な方法で。
回答
bash 4を使用すると、連想配列を利用する純粋なbashソリューションになります。 を使用できます。次に例を示します
unset llist; declare -A llist; while read -r line; do if [[ ${llist[$line]} ]]; then continue else printf "%s\n" "$line" llist[$line]="x" fi done < file.txt
コメント
- ドン’ t
read
ループを使用して大きなテキストファイルを処理します。 bashは、改行のオーバーシュートを回避するために、一度に1バイトを読み取る必要があります。また、Bashは、awkと比較して、一般的にテキスト処理がそれほど高速ではありません。これを使用する場合、read -ra
は入力でバックスラッシュを食べないようにします。また、これをシェル関数に配置する場合は、’ループのunset llist
後を忘れないでください。インタラクティブに使用してください。 - @PeterCordes、またはこれ 🙂
sort -u
の方がおそらく高速です。