別のファイルにないIDを1つのファイルで検索する


9

2つのファイルがあります。

abc.txt

abcd
xyz
pqrs

mno.txt

zzon
mkno
abcd
  • ファイルmno.txtに「abcd」があるかどうかを確認したい。
  • 「abcd」がabc.txtの最初にある場合は、最初にmno.txtにもある必要はありません。
  • 両方のファイルに数千のそのようなIDがあります。
  • また、abc.txtにあるmno.txtにないIDの数も確認したいと思います。

これどうやってするの ?

回答:


19

あなたの目標が一般的なまたは珍しい行を見つけるcommことであるなら、ここで私の頼りになるコマンドでしょう。

2つのファイルを比較し、ファイル1に固有の行を3列で、ファイル2に固有の行と、両方のファイルに表示される行をそれぞれ示します。フラグを渡して、この出力を抑制することもできます。たとえばcomm -1 file1 file2、file1に固有の最初の列を抑制します。comm -12 file1 file2両方のファイルにあるものだけを表示します。

注意点が1つあります。入力をソートする必要があります。これを回避できます。

これにより、mnoにないすべてのabcが表示されます。

comm -23 <(sort abc.txt) <(sort mno.txt)

そして、それをパイプしてwc -l、カウントを取得できます。


私が行く理由commは、いったんファイルがソートされると、並列比較は計算上非常に簡単だからです。あなたがこれらの何百万もの問題を扱っているなら、それは違いを生むでしょう。

これは、いくつかのモックファイルで実証できます。私はかなり高速なコンピューターを持っているので、アプローチの違いを示すために、かなり巨大なサンプルセットが必要です。ファイルごとに1000万の10文字の文字列に移動しました。

$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > abc.txt
$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > mno.txt

$ time comm -23 <(sort abc.txt) <(sort mno.txt) | wc -l
... 0m10.653s

$ time grep -Fcxv -f abc.txt mno.txt
... 0m23.920s

$ time grep -Fcwv -f abc.txt mno.txt
... 0m40.313s

$ time awk 'NR==FNR{a[$0]++};NR!=FNR && a[$0]' abc.txt  mno.txt | wc -l
... 0m12.161s

並べ替えは、私の時間のほとんどがかかります。abc.txtが静的なふりをする場合は、それを事前に並べ替えることができるため、将来の比較がはるかに速くなります。

$ sort abc.txt abc-sorted.txt
$ time comm -23 abc-sorted.txt <(sort mno.txt) | wc -l
... 0m7.426s

あなたはこれらを見て、数秒は無関係であると考えるかもしれませんが、これらがハイエンドマシンで実行されていることを強調しなければなりません。(例えば)Raspberry Pi 3でこれを実行したい場合は、ターンアラウンドがはるかに遅くなり、違いが実際に問題になるほど大きくなります。


7

リストを取得するには:

grep -Fwf abc.txt mno.txt

それはあなたに似たものを与えます:

abcd
abcd
zef

一意のリストを取得したい場合は、次のように使用します。

grep -Fwf abc.txt mno.txt | sort | uniq

カウントを取得するには:

grep -Fcwv -f abc.txt mno.txt

  • -F つまり、PATTERNを正規表現ではなく固定文字列のリストとして解釈します。
  • -fになるパターンをFILEから取得しますabc.txt
  • 私たちmno.txtはパターンを調べます
  • -c 一致の数を数える
  • -w「単語全体」のみを検索します。一致する部分文字列は、行の先頭か、単語の構成文字の前に置く必要があります。同様に、行の終わりか、単語以外の構成文字が後に続く必要があります。単語構成文字は、文字、数字、およびアンダースコアです。
  • -v 検索を逆にします

1
OPが望んでいる場合は、カウントマッチを、より多くのようにすべきではないということgrep -cxvFf abc.txt mno.txt
スティールドライバー2017年

ちょうどそれを見た:D ...私を救うためにいつもここにいる:D
Ravexina '26 / 06/12

FYI fgrepegrep交互には、おそらくの賛成で(廃止されgrep -Fgrep -E私は誰もが彼らがこれまで離れて行くだろうと考えているか分からないが-
steeldriver

使用-x時に使用する必要はあります-Fか?
Ravexina 2017年

1
それは、OPが正確にカウントしたいものに依存します-たとえば、mno.txtに含まれている場合、それはabcdef一致または非一致としてカウントする必要がありますabcdか?
スティールドライバー2017年

3

awkを使用して、最初にパターンファイル、次にチェックするファイルの2つのファイルを渡すことで、ジョブを実行できます。最初のファイルを読み込んでいるとき、それがわかっているのでNR==FNR、そのときに行を配列に読み込むことができます。そのNR!=FNRような行の配列が設定されているかどうかを確認すると。

$ cat abc.txt                                                      
abcd
xyz
pqrs
$ cat mno.txt                                                      
zzon
xyz
mkno
abcd
$ awk 'NR==FNR{a[$0]++};NR!=FNR && a[$0]' abc.txt  mno.txt         
xyz
abcd

逆に、パターンを無効にして、含まれていない行を印刷できます abc.txt

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt       
zzon
mkno

私たちは人々の数を印刷したい場合は、私たちは採用することができるsortwc

$ awk 'NR==FNR{a[$0]++};NR!=FNR && ! a[$0]' abc.txt  mno.txt | sort -u | wc -l         
2

私はあなたがそれを間違った方法で持っていると思います。私の知る限り質問を理解して、OPは、一連の差(の大きさ)を計算したいabc.txt- mno.txtです{xyz, pqrs}
David Foerster 2017年

2

どちらかの単語リストがソートされていない場合、効率的なセットデータ構造を使用して一般的な単語を覚える方が高速です。

パイソン

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as minuend_file:
    minuend = frozenset(map(str.rstrip, minuend_file))
with open(sys.argv[2]) as subtrahend_file:
    subtrahend = frozenset(map(str.rstrip, subtrahend_file))

difference = minuend - subtrahend
#print(*difference, sep='\n') # This prints the content of the set difference
print(len(difference)) # This prints the magnitude of the set difference

使用法:

python3 set-difference.py abc.txt mno.txt

Python(より効率的)

中間ストレージとランタイムのために少しメモリを節約したい場合は、これを少し理解しにくいプログラムを使用できます。

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as minuend_file:
    minuend = set(map(str.rstrip, minuend_file))
with open(sys.argv[2]) as subtrahend_file:
    subtrahend = map(str.rstrip, subtrahend_file)
    minuend.difference_update(subtrahend)
    difference = minuend
    del minuend

#print(*difference, sep='\n') # This prints the content of the set difference
print(len(difference)) # This prints the magnitude of the set difference

パフォーマンス

与えられabc.txtmno.txt1つのmioで並べ替えられていない、それぞれ10個のランダムなASCII数字文字(未設定のOliの回答を参照):

$ time python3 set-difference.py abc.txt mno.txt
user    0m10.453s

$ export LC_COLLATE=C
$ time sort abc.txt > abc_sorted.txt
user    0m10.652s
$ time sort mno.txt > mno_sorted.txt
user    0m10.767s
$ time comm -23 abc_sorted.txt mno_sorted.txt | wc -l
9989882
user    0m1.600s

合計:23秒

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