最初のファイルに含まれる i 以外の名前を取得するにはどうすればよいですか?

最初のファイルに含まれる i 以外の名前を取得するにはどうすればよいですか?

数十億の DNA 配列名を含む 2 つのファイルがあり、2 番目のファイルは最初のファイルの適切なサブセットです。

例えば、

1°:john mike anna paul laura .... 

2°:john mike paul ...

すべての名前が 1 行を占めます。

私の質問は、最初のファイルには含まれていて 2 番目のファイルには含まれていない名前を取得するにはどうすればよいかということです。

皆さんありがとう!

答え1

これは非常に簡単に実行できますが、スペースで区切られたリストではなく、1 行に 1 つの名前があると作業がはるかに簡単になります。Linux にはテキスト ファイルを操作する優れたユーティリティが多数あり、これはすべての *nix が得意とする機能の 1 つですが、ほとんどのシステムでは 1 行に 1 つの項目が想定されています。そのため、私のソリューションのほとんどは、それに応じてファイルを変更することから始まります。

1 行に 1 つの名前が付くようにファイルを変更します。

sed 's/ /\n/g' file > newfile

または、元のファイルを変更する

sed -i 's/ /\n/g' file

それが完了すると、次のいずれかで必要なものが得られます。

  1. グレップ

    $ grep -vFwf file2 file1
    anna
    laura
    
  2. commまたはdiff

    $ comm -23 <(sort file1) <(sort file2)
    anna
    laura
    
    
    $ diff file1 file2 | grep -Po '<\s+\K.*'
    anna
    laura
    
  3. awk

    $ awk '(NR==FNR){a[$1]++; next}!($1 in a){print}' file2 file1 
    laura
    anna
    
  4. パール

    $ perl -lne 'BEGIN{open(A,"file2"); while(<A>){chomp; $k{$_}++}} print unless $k{$_}' file2 file1
    laura
    anna
    

    または

    $ perl -lne '$k{$_}++; END{map{print unless $k{$_}>1}keys(%k)}' file2 file1
    laura
    anna
    

ファイルのフォーマットを変更したくない場合は(本当は変更すべきですが)、次のようにします。

awk '{for (i=1;i<=NF;i++){a[$i]++}}END{for(n in a){if(a[n]<2){print n}}}' file2 file1

または

perl -lane '$k{$_}++ for @F; END{map{print if $k{$_}<2} keys(%k)}' file1 file2

答え2

改行で区切られてソートされている場合は、commfile1 に固有の行を表示できます。

comm -23 file1 file2

デモンストレーション:

$ comm -23 <(echo -e 'john\nmike\nanna\npaul\nlaura'|sort) <(echo -e 'john\nmike\npaul'|sort)
anna
laura

または、diffほぼ同じことを実行できます (grep行の削除を探しています)。

diff sorted-file-1 sorted-file-2 | grep -oP '(?<=< ).+'

ソートを避ける必要がある場合や、重要な数値を扱う場合は、辞書ベースの検索を行う適切な言語を使用することをお勧めします。簡単な Python の例:

file2 = {}
with open("file2") as f:
    for line in f:
        file2[line] = 0

with open("file1") as f:
    for line in f:
        if not line in file2:
            print line

それよりも大きい場合は、実際のデータベースと簡単な SQL を検討することをお勧めします。これらはビッグ データ向けに設計されています。

答え3

そして、Python オプション: すべての単語が 1 行にあるか、別々の行にあるかに関係なく:

#!/usr/bin/env python3

import sys

f1 = sys.argv[1]; f2 = sys.argv[2]

def read(f):
    with open(f) as content:
        return content.read().split()

for item in [w for w in read(f1) if not w in read(f2)]:
    print(item)

スクリプトを空のファイルにコピーし、showdiff.py実行可能ファイルとして保存して、次のコマンドで実行します。

/path/to/showdiff.py file1 file2

anna
laura

注記

質問ではありませんが、省略できないほど関連が多すぎます。

違いをリストアップする必要がある場合互いにfile1、(に現れない の単語だけでなく に現れない のfile2単語も)、以下のスクリプトを使用する必要があります。file2file1

#!/usr/bin/env python3

import sys

f1 = sys.argv[1]; f2 = sys.argv[2]

def read(f):
    with open(f) as content:
        return content.read().split()

wds1 = read(f1); wds2 = read(f2); allwords = wds1+wds2
for item in [w for w in allwords if (w in wds1, w in wds2).count(False) == 1]:
    print(item)

答え4

Jacob Vlijmが提案したPythonオプションを使用する場合は、「set」を使用する価値があります(詳細については、https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset)。基本的に、2 つのセットを作成したら、セットの計算 (和集合、積集合、差集合など) を実行できます。
この場合、差集合がまさに必要なものです。つまり、1 つのセットに含まれ、もう 1 つのセットには含まれないすべての要素を含む新しいセットです。Jacob
のコードは次のようになります。

#!/usr/bin/env python3

import sys

f1 = sys.argv[1]; f2 = sys.argv[2]

def read_set(f):
    with open(f) as content:
        return set(content.read().split())

for item in read_set(f1) - read_set(f2)]:
    print(item)

もちろん、数十億件のレコードの場合は、しばらく時間がかかります... `

関連情報