¿Cómo puedo obtener los nombres contenidos en el primer archivo que no son i?

¿Cómo puedo obtener los nombres contenidos en el primer archivo que no son i?

Tengo dos archivos que contienen miles de millones de nombres de secuencias de ADN, el segundo es un subconjunto adecuado del primero:

Por ejemplo,

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

2°:john mike paul ...

todos los nombres ocupan una sola fila.

Mi pregunta es ¿cómo puedo obtener los nombres que contiene el primer archivo que no están en el segundo?

gracias a todos!

Respuesta1

Esto es muy sencillo de hacer, pero tu vida será mucho más fácil si tienes un nombre por línea en lugar de una lista separada por espacios. Hay muchas utilidades excelentes para manipular archivos de texto en Linux, es una de las cosas en las que todos los *nixes destacan, pero la mayoría espera un elemento por línea. Entonces, la mayoría de mis soluciones comenzarán modificando los archivos en consecuencia.

Cambie sus archivos para que tengan un nombre por línea:

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

o, para modificar el archivo original

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

Una vez que hayas hecho eso, cualquiera de estos te dará lo que deseas:

  1. grep

    $ grep -vFwf file2 file1
    anna
    laura
    
  2. commodiff

    $ 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. perla

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

    o

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

Si realmente no desea cambiar el formato de su archivo (pero realmente debería hacerlo), puede hacer algo como

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

o

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

Respuesta2

Si están ordenados y separados por nuevas líneas, puede usar commmostrarle las líneas que son exclusivas del archivo1:

comm -23 file1 file2

Una demostración:

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

O podrías diffhacer lo mismo (está grepbuscando eliminaciones de líneas):

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

Si necesita evitar ordenar o se trata de números importantes, recurriría a un lenguaje adecuado para realizar búsquedas basadas en diccionarios. Ejemplo sencillo 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

Si es más grande que eso, es posible que desee consultar una base de datos real y algo de SQL simple. Están preparados para big data.

Respuesta3

Y la opción de Python: independientemente de si todas las palabras están en una línea o en líneas 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 el script en un archivo vacío, guárdelo como showdiff.pyejecutable y ejecútelo con el comando:

/path/to/showdiff.py file1 file2

anna
laura

Nota

No es la pregunta, pero está demasiado relacionada como para omitirla:

Si necesita enumerar las diferenciasmutuamente, (no solo las palabras file1que no aparecen en file2, sino también las palabras file2que no aparecen en file1), se debe utilizar el siguiente script:

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

Respuesta4

Si elige la opción Python como sugiere Jacob Vlijm, vale la pena usar el 'set' (para más información, consultehttps://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset). Básicamente, una vez que haya creado los dos conjuntos, puede lograr la matemática de conjuntos (unión, intersección, diferencia,...).
En este caso, la diferencia de conjuntos es exactamente lo que necesita: un nuevo conjunto con todos los elementos que están en un conjunto y no en el otro.
El código de Jacob sería entonces:

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

Por supuesto, para miles de millones de registros, llevará un tiempo... `

información relacionada