Como posso obter os nomes contidos no primeiro arquivo que não são eu?

Como posso obter os nomes contidos no primeiro arquivo que não são eu?

Tenho dois arquivos contendo bilhões de nomes de sequências de DNA, o segundo é um subconjunto adequado do primeiro:

por exemplo,

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

2°:john mike paul ...

todos os nomes ocupam uma única linha.

Minha dúvida é: como posso obter os nomes contidos no primeiro arquivo que não estão no segundo?

obrigado a todos!

Responder1

Isso é muito simples de fazer, mas sua vida será muito mais fácil se você tiver um nome por linha em vez de uma lista separada por espaços. Existem muitos utilitários excelentes para manipular arquivos de texto no Linux, é uma das coisas em que todos os *nixes se destacam, mas a maioria espera um item por linha. Portanto, a maioria das minhas soluções começará com a modificação dos arquivos de acordo.

Mude seus arquivos para terem um nome por linha:

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

ou, para modificar o arquivo original

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

Depois de fazer isso, qualquer um destes lhe dará o que você deseja:

  1. grep

    $ grep -vFwf file2 file1
    anna
    laura
    
  2. commoudiff

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

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

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

    ou

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

Se você realmente não deseja alterar o formato do seu arquivo (mas realmente deveria), você pode fazer algo como

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

ou

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

Responder2

Se eles estiverem classificados e separados por novas linhas, você poderá commmostrar as linhas exclusivas do arquivo1:

comm -23 file1 file2

Uma demonstração:

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

Ou você poderia difffazer praticamente a mesma coisa (está grepprocurando exclusões de linha):

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

Se você precisar evitar a classificação ou estiver lidando com números sérios, eu recorreria a uma linguagem adequada para fazer pesquisas baseadas em dicionário. Exemplo simples de 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

Qualquer coisa maior que isso e você pode querer olhar um banco de dados real e um SQL simples. Eles são voltados para big data.

Responder3

E a opção python: independentemente de todas as palavras estarem em uma linha ou em linhas separadas:

#!/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)

Copie o script em um arquivo vazio, salve-o como showdiff.pyexecutável e execute-o com o comando:

/path/to/showdiff.py file1 file2

anna
laura

Observação

Não é a questão, mas há muita coisa relacionada para deixar de fora:

Se você precisar listar as diferençasmutuamente, (não apenas palavras file1que não aparecem em file2, mas também palavras file2que não aparecem em file1), O script abaixo deve ser usado:

#!/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)

Responder4

Se você optar pela opção python sugerida por Jacob Vlijm, vale a pena usar o 'set' (para mais informações, consultehttps://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset). Basicamente, depois de criar os dois conjuntos, você pode obter a matemática do conjunto (união, interseção, diferença,...).
Nesse caso, a diferença do conjunto é exatamente o que você precisa: um novo conjunto com todos os elementos que estão em um conjunto e não no outro.
O código de Jacob seria então:

#!/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)

É claro que, para bilhões de registros, vai demorar um pouco... `

informação relacionada