web-dev-qa-db-ja.com

ソートせずに重複する行を削除する

Pythonのユーティリティスクリプトがあります。

#!/usr/bin/env python
import sys
unique_lines = []
duplicate_lines = []
for line in sys.stdin:
  if line in unique_lines:
    duplicate_lines.append(line)
  else:
    unique_lines.append(line)
    sys.stdout.write(line)
# optionally do something with duplicate_lines

この単純な機能(最初にソートする必要のないuniq、安定した順序付け)は、単純なUNIXユーティリティとして利用可能でなければなりません。パイプ内のフィルターの組み合わせでしょうか?

尋ねる理由:どこからでもpythonを実行できないシステムでこの機能が必要

91
Robottinosino

UNIX Bash Scriptingブログ 提案

awk '!x[$0]++'

このコマンドは、印刷する行をawkに伝えています。変数$0は行の内容全体を保持し、角括弧は配列アクセスです。そのため、ファイルの各行について、配列のノードxがインクリメントされ、そのノードのコンテンツが(!)以前に設定されました。

231
Michael Hoffman

遅い答え-私はちょうどこれの複製に遭遇しました-しかし、おそらく追加する価値があります...

@ 1_CRの答えの背後にある原理は、行番号を追加するためにawkの代わりにcat -nを使用して、より簡潔に書くことができます。

cat -n file_name | sort -uk2 | sort -nk1 | cut -f2-
  • cat -nを使用して行番号を付加します
  • sort -uを使用して重複データを削除します
  • sort -nを使用して、先頭に数字を付けて並べ替えます
  • cutを使用して行番号を削除します
55
Digital Trauma

上記のマイケル・ホフマンの解決策は短くて甘いです。大きなファイルの場合、awkに続いて複数回のソートとuniqを使用したインデックスフィールドの追加を伴うシュワルツ変換アプローチでは、メモリオーバーヘッドが少なくなります。次のスニペットはbashで動作します

awk '{print(NR"\t"$0)}' file_name | sort -t$'\t' -k2,2 | uniq --skip-fields 1 | sort -k1,1 -t$'\t' | cut -f2 -d$'\t'
5
iruvar

2つのファイルから重複を削除するには:

awk '!a[$0]++' file1.csv file2.csv
5
AzizSM

これで、Rustで書かれたこの小さなツール q を確認できます。

最初に入力をソートすることなく一意性フィルタリングを実行するため、連続ストリームに適用できます。

2
Shou Ya

ありがとう1_CR! uniq(重複のコピーを1つ残す)ではなく、「uniq -u」(重複を完全に削除する)が必要でした。これを行うためにawkとPerlのソリューションを実際に変更することはできません。また、100,000,000行のように一意にするため、メモリの使用量を少なくする必要があるかもしれません8-)。他の誰かがそれを必要とする場合に備えて、コマンドのuniq部分に「-u」を入力します。

awk '{print(NR"\t"$0)}' file_name | sort -t$'\t' -k2,2 | uniq -u --skip-fields 1 | sort -k1,1 -t$'\t' | cut -f2 -d$'\t'
2
hwertz

uniqコマンドはエイリアスでも機能します http://man7.org/linux/man-pages/man1/uniq.1.html

0
Master James

ファイルのすべての場所ではなく、次の行のすべての重複を削除したかっただけです。だから私は使用しました:

awk '{
  if ($0 != PREVLINE) print $0;
  PREVLINE=$0;
}'
0
speedolli