Eu tenho 4 arquivos tsv (separados por tabulação) que se parecem com isto:
arquivo_1:
abc 1
def 2
ghi 3
arquivo_2:
abc 2
ghi 3
arquivo_3:
def 1
ghi 2
jkl 4
arquivo_4:
ghi 3
jkl 4
Quero juntar esses arquivos para obter 1 arquivo tsv como este:
dataset file_1 file_2 file_3 file_4
abc 1 2
def 2 4
ghi 3 3 2 3
jkl 4 4
Eu tentei usarawk
$ awk '
BEGIN{OFS=FS="\t"}
FNR==1{f = f "\t" FILENAME}
NR==FNR{a[$1] = $2}
NR!=FNR{a[$1] = a[$1] "\t" $2}
END{printf "dataset%s\n", f; for(i in a) print i, a[i]}
' file_{1..4}
Este comando funciona, mas mudei o valor. Digamos que se a primeira e a segunda colunas tiverem valor vazio e a terceira e quarta colunas tiverem valores 4 e 4, a saída que obtive desse comando é que a primeira e a segunda colunas têm valor 4, mas a terceira e a quarta colunas têm valor vazio. Então, tento juntar meu arquivo tsv separadamente usando awk
o que mencionei. Primeiro apenas para file_1
e file_2
para obter output_1
, depois junte file_3
e file_4
para obter output_2
. Depois disso, uso $ join output_1 output_2
para mesclar output_1 e output_2, mas só obtenho valores que existem em 4 arquivos. Perdi dados que existem apenas em um arquivo.
Eu apreciarei muito se você puder me dar um conselho.
Obrigado
Responder1
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ datasets[$1]; fnames[FILENAME]; vals[$1,FILENAME] = $2 }
END {
printf "%s", "dataset"
for (fname in fnames) {
printf "%s%s", OFS, fname
}
print ""
for (dataset in datasets) {
printf "%s", dataset
for (fname in fnames) {
printf "%s%s", OFS, vals[dataset,fname]
}
print ""
}
}
$ tail -n +1 file?
==> file1 <==
a 1
b 2
c 3
==> file2 <==
a 2
c 3
$ awk -f tst.awk file1 file2
dataset file1 file2
a 1 2
b 2
c 3 3
Adicione quantos arquivos desejar à lista.
Responder2
Com join (GNU coreutils) 8.30
e "substituição de processo", você pode tentar
join -a1 -a2 -t" " -oauto -e " " <(join -a1 -a2 -t" " -oauto -e "" file[12]) <(join -a1 -a2 -t" " -oauto -e " " file[34])
abc 1 2
def 2 1
ghi 3 3 2 3
jkl 4 4
As -t
opções possuem um <TAB>
valor de caractere.
Responder3
Conselho por enquanto: codifique para mais tarde, se precisar.
Eu manteria três arrays enquanto você lê todos os arquivos.
(a) Para cada novo arquivo, uma lista hash de nomes de arquivos.
(b) Para cada novo conjunto de dados, uma lista hash de $1.
(c) Para cada linha, uma lista hash de valores
FNR == 1 { ++htFile[FILENAME]; }
! ($1 in htSet) { ++htSet[$1]; }
{ htVal [FILENAME, $1] = $2; }
Em uma função End, itere sobre htFile e htSet.
function Table (r, c, buf) {
buf = "dataset";
for (c in htFile)
buf = sprint ("%s\t%s", buf, htFile[c]);
print buf;
for (r in htSet) {
buf = "";
for (c in htFile)
buf = sprint ("%s\t%s", buf, htVal[c, r]);
print substr (buf, 2);
}
}
END { Table( ); }
Isso não mantém a ordem dos arquivos e conjuntos de dados na tabela de saída. Se isso for importante, você pode manter uma versão sequenciada das tabelas e iterar na ordem original.