Mesclar várias linhas no mesmo arquivo com base na coluna 1

Mesclar várias linhas no mesmo arquivo com base na coluna 1

Ainda estou aprendendo programação e tentei muitas coisas, mas não consigo obter o formato correto. eu tenho umdelimitado por tabulaçãoarquivo com 17 colunas e muitas (cerca de 50.000) linhas. O arquivo já está classificado pela primeira coluna. Quero mesclar linhas que possuem a mesma primeira coluna (A), mas todas as outras 16 colunas são diferentes e quero manter todas as informações em uma linha, de preferência na mesma coluna componto e vírgula;como um delimitador entre eles. Quero manter a tabulação como delimitador no arquivo de saída. Muito obrigado pelas respostas e se você também pudesse explicar onde errei seria ainda melhor :).

Eu tentei até agora:

awk -F'\t' 'NF>1{a[$1] = a[$1]";"$2}END{for(i in a){print i""a[i]}}' filename.txt

perl -F',' -anle 'next if /^$/;$h{$F[0]} = $h{$F[0]}.", ".$F[1];
END{print $_,$h{$_},"\n" for sort keys %h}' filename.txt

FORMATO DE ARQUIVO (outras 15 colunas têm o mesmo formato da coluna B)

A     B     C    
123   fvv   ggg
123   kjf   ggg
123   ccd   att
567   abc   gst
567   abc   hgt
879   ttt   tyt

A saída que desejo (preciso de todas as 17 colunas e para as colunas 2 a 16 preciso da mesma saída das colunas B e C). Todos os casos de B devem estar abaixo de B e todos os casos de C devem estar abaixo de C e todos os casos de D devem estar abaixo de D etc. Portanto, a saída tem 17 colunas assim como a entrada e em vez de 50.000 linhas, agora deve ter cerca de 20.000 , porque há muitas repetições para a coluna 1 (para este arquivo específico):

A     B                C
123   fvv;kjf;ccd      ggg;ggg;att
567   abc;abc          gst;hgt
879   ttt              lll

Responder1

awk '{
      if(NR!=1){a[$1]=$2";"a[$1]}
      else print $0}
    END{
      n = asorti(a, b);
      for (n in b) {
      print b[n],a[b[n]]
      }
    }'

Responder2

Uma solução Perl:

$ perl -F"\t" -anle 'if($.==1){print; next} push @{$k{$F[0]}},@F[1..$#F]; 
  END{print "$_\t" . join(";",@{$k{$_}}) for sort keys(%k)}' file 
A   B   
123 fvv;kjf;ccd
567 abc;abc
879 ttt

Isso pode funcionar em um número arbitrário de campos. No entanto, é necessário carregar algumas coisas na memória e isso pode ser um problema se o arquivo for grande.


Quanto a onde você errou, não podemos dizer a menos que você explique o que realmente aconteceu, mas, pensando bem, sua tentativa de Perl falharia porque:

  • Você está usando -F,o qual define o separador de campos como uma vírgula quando sua entrada possui tabulações.
  • Você está usando -le print "foo\n". O -ljá adiciona uma nova linha a cada chamada de impressão, então você terá várias linhas em branco.
  • Você está usando $h{$F[0]}.", ".$F[1];para anexar, então na primeira vez que for executado e $h{$F[0]}não estiver definido, você adicionará um extra ,no início do seu valor armazenado.
  • Você está olhando apenas para o segundo campo, ignorando todos os outros.

Da mesma forma, você awkfalhará porque:

  • Você está imprimindo foo""baro que concatenará a saída sem espaço entre cada campo. Você deseja print foo,bare também deseja OFS="\t"uma saída separada por tabulações.
  • Você está olhando apenas para o segundo campo, ignorando todos os outros.

Responder3

desculpas por esta frase, mas aqui vai -

awk 'BEGIN{FS="\t"} {for(i=2; i<=NF; i++) { if (!a[$1]) a[$1]=$1FS$i ;else a[$1]=a[$1]";"$i};if ($1 != old) b[j++] = a[old];old=$1 } END{for (i=0; i<j; i++) print b[i] }' 1

123 fvv ;kjf;ccd
567 abc;abc
879 ttt

Responder4

awk '
    function p(n,A){
        s = n
        for(i=2;i<=NF;i++){
            s = s "\t" A[i]
            A[i] = $i
        }
        if(n)
            print s
    }
    NR==1{
        print
        next
    }
    $1==n{
        for(i=2;i<=NR;i++)
            A[i] = A[i] ";" $i
        next
    }
    {
        p(n,A)
        n = $1
    }
    END{
        p(n,A)
    }
    ' file

informação relacionada