Combine informações de dois arquivos, linha por linha

5

Eu tenho 2 arquivos como entrada:

Arquivo 1 (separado por espaço)

ID POS a0 a1
SNP1 123 A C
SNP2 456 T C
SNP3 789 G A

Arquivo 2 (separado por espaço)

0 1 0 1 0 0 0 1
1 1 0 0 1 0 0 1
0 1 1 1 0 0 0 1

Saída exigida

A C A C A A A C
C C T T C T T C
G A A A G G G A 

Cada linha no arquivo 2 representa 1 Linha no Arquivo 1, o truque é substituir 0 e 1 pela letra correspondente em a0 e a1 respectivamente. Este é apenas um pequeno exemplo, o arquivo real é enorme, mais de 600 mil linhas.

Estou procurando uma solução de awk ou perl.

    
por Bernabé Bustos Becerra 25.11.2015 / 18:26

3 respostas

3

Como um ilegível awk one-liner

$ awk 'NR>1{a[0]=$3;a[1]=$4;getline<f;for(i=1;i<=NF;i++)$i=a[$i];print}' f=file2 file1
A C A C A A A C
C C T T C T T C
G A A A G G G A

Mais legível:

awk '
    # skip the header in file1
    NR == 1 {next}
    {
        # read the values from the file1 line
        a[0] = $3
        a[1] = $4

        # replace the current record with the corresponding line from the map file
        getline < map_file

        # and now substitute the 0/1 with the values
        for (i=1; i<=NF; i++)
            $i = a[$i]
        print
    }
' map_file=file2  file1
    
por 25.11.2015 / 21:31
2

Você pode fazer isso totalmente em awk , mas como uma variação, veja aqui uma solução awk + paste . Você precisará de bash ou outro shell que suporte substituição de processo

paste <(tail -n +2 file1) file2 | 
awk '{a["0"]=$3; a["1"]=$4; for (i=5; i<=NF; ++i) printf "%s%s", a[$i], i==NF?"\n": " "}'

O tail -n +2 é necessário para pular a linha de cabeçalho de file1 .

    
por 25.11.2015 / 19:01
0
#!/usr/bin/env perl
# TODO docs on usage here, or write perldocs below, etc.
use strict;
use warnings;

die "Usage: $0 headerfile datafile\n" if @ARGV != 2;

my ($headerfile, $datafile) = @ARGV;

open(my $hfh, '<', $headerfile) or die "could not open '$headerfile': $!\n";
open(my $dfh, '<', $datafile) or die "could not open '$datafile': $!\n";

readline $hfh; # skip the header line

my $lineno = 1;
while (!eof($hfh) and !eof($dfh)) {
  my $convert_to = join '', (split ' ', scalar readline $hfh)[-2,-1];
  die sprintf "no conversion at $headerfile:%d\n", $lineno+1
    if !defined $convert_to;

  $_ = readline $dfh;
  die "no data to convert at $datafile:$lineno\n" if !defined;

  eval "tr/01/$convert_to/, 1" or die $@;
  print;

  $lineno++;
}
    
por 25.11.2015 / 19:07