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:
grep
$ grep -vFwf file2 file1 anna laura
comm
odiff
$ comm -23 <(sort file1) <(sort file2) anna laura $ diff file1 file2 | grep -Po '<\s+\K.*' anna laura
awk
$ awk '(NR==FNR){a[$1]++; next}!($1 in a){print}' file2 file1 laura anna
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 comm
mostrarle 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 diff
hacer lo mismo (está grep
buscando 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.py
ejecutable 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 file1
que no aparecen en file2
, sino también las palabras file2
que 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... `