![comprobar si la cadena está presente en una lista y generar un tercer archivo si la cadena está presente](https://rvso.com/image/97245/comprobar%20si%20la%20cadena%20est%C3%A1%20presente%20en%20una%20lista%20y%20generar%20un%20tercer%20archivo%20si%20la%20cadena%20est%C3%A1%20presente.png)
Tengo 2 archivos ("data.tab" y "mylist.tab").
mi archivo "data.tab" se ve así:
Info_1 abc1 abc2 abc3
Info_2 abc5 ghi4
Info_3 abc10
Info_4 abc8 abc7 abc87 klm78 abc99
Info_5
mi archivo "mylist.tab" se ve así:
abc2
abc10
abc34
abc99
abc78
abc8
abc3
abc5
abc4
Me gustaría buscar si cada cadena en "data.tab" (excepto la columna 1) está presente en "mylist.tab". Me gustaría crear un tercer archivo "output.tab" donde, si la cadena está presente, incluiría un "1" y, de lo contrario, un "0" en esa fila/columna respectiva.
Ejemplo: "salida.tab"
Info_1 0 1 1
Info_2 1 0
Info_3 1
Info_4 1 0 0 0 1
Info_5
Tenga en cuenta que "data.tab" contiene un número diferente de columnas para cada fila.
Respuesta1
Esto se expresa claramente en awk:
awk 'FNR==NR { h[$1]; next } { for(i=2; i<=NF; i++) $i = ($i in h)? 1 : 0 } 1' mylist.tab data.tab
O en un formato más legible:
parse.awk
# Collect mylist.tab into the `h` associative array
FNR==NR {
h[$1]
next
}
# For all but the first column in data.tab check and record if it is in `h`
{
for(i=2; i<=NF; i++)
$i = ($i in h) ? 1 : 0
}
# Short for { print $0 }
1
Ejecútelo así:
awk -f parse.awk mylist.tab data.tab
Producción:
Info_1 0 1 1
Info_2 1 0
Info_3 1
Info_4 1 0 0 0 1
Info_5
O para columnas delimitadas por tabulaciones:
awk -v OFS='\t' -f parse.awk mylist.tab data.tab
Producción:
Info_1 0 1 1
Info_2 1 0
Info_3 1
Info_4 1 0 0 0 1
Info_5
Respuesta2
Perl al rescate!
Guarde los elementos de la lista en un hash, luego lea la tabla, divídala en espacios en blanco y verifique el hash para imprimir 0 o 1.
#!/usr/bin/perl
use warnings;
use strict;
my %in_list;
open my $LIST, '<', 'mylist.tab' or die $!;
while (<$LIST>) {
chomp;
$in_list{$_} = 1;
}
open my $TAB, '<', 'data.tab';
while (<$TAB>) {
my @cells = split;
print shift @cells, "\t";
print join "\t", map $in_list{$_} ? 1 : 0, @cells;
print "\n";
}
Respuesta3
Úselo sed
para crear un sed
script desde mylist.tab y ejecutarlo en data.tab:
sed \
-e '1i s/^[ \\t]*//' \
-e 's@\(.*\)@s/\\([ \\t]\\)\1\\b/\\11/@g' \
-e '$as/\\([ \\t]\\)[^ \\t]\\{2,\\}\\b/\\10/g' mylist.tab \
> /tmp/x.sed
sed -f /tmp/x.sed data.tab
Nota: Supongo que todas las cadenas de "mylist.tab" tienen al menos 2 caracteres.
Respuesta4
Otra perl
solución
$ perl -lne 'if(!$#ARGV){ $h{$_}=1 }
else{ s/\h\K\H+/$h{$&} ? 1 : 0/ge; print }
' mylist.tab data.tab
Info_1 0 1 1
Info_2 1 0
Info_3 1
Info_4 1 0 0 0 1
Info_5
if(!$#ARGV){ $h{$_}=1 }
construir un hash de palabras enmylist.tab
s/\h\K\H+/$h{$&} ? 1 : 0/ge
para las líneas endata.tab
, reemplácelas con1
si están presentes en la variable hash, de lo contrario0
. La\h\K
búsqueda hacia atrás es positiva para detectar la presencia de espacios en blanco, lo que evita que la primera columna coincida.- Luego imprima la línea modificada.