Mesclando duas tabelas incluindo múltiplas ocorrências de identificadores de coluna e linhas exclusivas

2

Eu fiz uma pergunta semelhante ontem ( Mesclando dois tabelas, incluindo a ocorrência múltipla de identificadores de coluna ), mas encontrou um problema com linhas exclusivas.

Gostaria de mesclar duas tabelas com base na coluna 1:

Arquivo 1:

1 today
1 green
2 tomorrow
3 red

Arquivo 2:

1 a lot
1 sometimes
2 at work
2 at home
2 sometimes
3 new
4 a lot
5 sometimes
6 at work

Saída desejada (arquivo 3):

1 today a lot
1 today sometimes
1 green a lot
1 green sometimes
2 tomorrow at work
2 tomorrow at home
2 tomorrow sometimes
3 red new

Eu fiz o seguinte:

awk -F '[\t]' -v OFS='\t' '{i=$1;$1=x} NR==FNR{A[i]=$0;next} A[i]{print i,$0A[i]}' file2 file1 > file3

No entanto, só me dá:

1 today sometimes
2 tomorrow sometimes
3 red new

Por favor, note que as soluções no tópico anterior (join e awk) me dariam uma combinação dos dois arquivos, incluindo todas as linhas. Eu gostaria de ter apenas as linhas do arquivo 1 (coluna 1 como o identificador), mas relate todas as ocorrências correspondentes no arquivo 2.

Editar:

colunas são separadas por separadores

Arquivo Real 1:     fig | 395961.4.peg.2627 Bactérias Cianobactérias desconhecidas desconhecidas 1795

(Coluna1: fig ... Coluna2: Bactérias ... Coluna3 1795)

Arquivo Real 2:     fig | 1000561.3.peg.1838 Teste de cisteína desulfurase (EC 2.8.1.7) - Cofatores de tiamina, vitaminas, grupos protéticos, pigmentos

(Coluna1: fig ... Coluna2: Cisteína ... Teste Coluna3 ...)

    
por BSP 16.09.2014 / 11:15

3 respostas

1

Eu faria isso em Perl:

#!/usr/bin/env perl 
use strict;

my (%file1,%file2);

## Open the 1st file
open(A,"file1");
while(<A>){
    ## Remove trailing newlines
    chomp; 
    ## Split the current line on tabs into the @F array.
    my @F=split(/\t/); 
    ## This is the tricky part. It adds fields 2-last
    ## to the hash $file1. The value of this hash is an array
    ## and the keys are the 1st fields. This will result in a list
    ## of all 1st fields and all their associated columns.
    push @{$file1{$F[0]}},@F[1..$#F];
} 


## Open the 2nd file
open(B,"file2");
while(<B>){
    ## Remove trailing newlines
    chomp; 
    ## Split the current line on tabs into the @F array.
    my @F=split(/\t/); 

    ## If the current 1st field was found in file1
    if (defined($file1{$F[0]})) {
        ## For each of the columns associated with
        ## this 1st field in the 1st file.
        foreach my $col (@{$file1{$F[0]}}) {
            print "$F[0]\t$col\t@F[1..$#F]\n";
        }
    }
} 

Você pode jogar golfe em uma linha longa:

$ perl -lane 'BEGIN{open(A,"file1"); while(<A>){chomp; @F=split(/\t/); 
                    push @{$k{$F[0]}},@F[1..$#F];}  } 
              $k{$F[0]} && print "$F[0]\t@{$k{$F[0]}}\t@F[1..$#F]"' file2
1   today green a lot
1   today green sometimes
2   tomorrow    at work
2   tomorrow    at home
2   tomorrow    sometimes
3   red new

Se você estiver trabalhando com arquivos grandes, deixe-o rodar um pouco.

    
por 17.09.2014 / 00:46
2

Usando o awk

UTILIZAR FUNÇÕES

Legível:

    awk 'function get(file,x,y) {
        while ( (getline < file) > 0) {if ($1==x)y,substr($0,index($0," ")+1)}
        close(file)
        }
        ARGV[1]==FILENAME{get(ARGV[2],$1,$0)}' file1 file2

Linha única:

awk 'function g(f,x,y){while((getline <f)>0)if($1==x){print y,substr($0,index($0," ")+1)}close(f)}NR==FNR{g(ARGV[2],$1,$0)}' file1 file2

.

USANDO UMA MATRIZ

awk 'FNR==NR{a[$0]=$1;next}{for(i in a)if(a[i]==$1)print i,substr($0,index($0," ")+1)}' file file2

.

RESULTADO

1 today a lot
1 today sometimes
1 green a lot
1 green sometimes
2 tomorrow at work
2 tomorrow at home
2 tomorrow sometimes
3 red new
    
por 16.09.2014 / 12:32
0

O que há de errado com o comando de união?

join file1 file2

Dá o resultado necessário

    
por 17.09.2014 / 03:57