Fusionar varias líneas en el mismo archivo según la columna 1

Fusionar varias líneas en el mismo archivo según la columna 1

Todavía estoy aprendiendo a programar y he probado muchas cosas pero no puedo conseguir el formato correcto. tengo undelimitado por tabulacionesarchivo con 17 columnas y muchas (alrededor de 50.000) filas. El archivo ya está ordenado por la primera columna. Quiero fusionar filas que tienen la misma primera columna (A), pero las otras 16 columnas son diferentes y quiero mantener toda la información en una fila, preferiblemente en la misma columna conpunto y coma;como delimitador entre ellos. Quiero mantener la pestaña como delimitador en el archivo de salida. Muchas gracias por las respuestas y si también pudieras explicar la respuesta en la que me equivoqué, sería aún mejor :).

Lo he intentado hasta ahora:

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 ARCHIVO (otras 15 columnas tienen el mismo formato que la columna B)

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

El resultado que quiero (necesito las 17 columnas y para las columnas 2 a 16 necesito el mismo resultado que en las columnas B y C). Todos los casos de B deben estar debajo de B y todos los casos de C deben estar debajo de C y todos los casos de D deben estar debajo de D, etc. Entonces, la salida tiene 17 columnas al igual que la entrada y en lugar de 50,000 filas, ahora debería tener alrededor de 20,000. , porque hay muchas repeticiones para la columna 1 (para este archivo en particular):

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

Respuesta1

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]]
      }
    }'

Respuesta2

Una solución 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

Esto puede funcionar en un número arbitrario de campos. Sin embargo, requiere cargar bastantes cosas en la memoria y eso podría ser un problema si el archivo es grande.


En cuanto a dónde salió mal, no podemos decírselo a menos que explique lo que realmente sucedió, pero, en lo que se me ocurre, su intento de Perl fallaría porque:

  • Está utilizando -F,el cual establece el separador de campo en una coma cuando su entrada tiene pestañas.
  • Estás usando -ly print "foo\n". Ya -lagrega una nueva línea a cada llamada de impresión, por lo que tendrá varias líneas en blanco.
  • Está utilizando $h{$F[0]}.", ".$F[1];para agregar, por lo que la primera vez que se ejecuta y $h{$F[0]}no está definido, agregará un extra ,al comienzo de su valor almacenado.
  • Sólo estás mirando el segundo campo, ignorando todos los demás.

De manera similar, su testamento awkfallará porque:

  • Está imprimiendo foo""bar, lo que concatenará la salida sin espacios entre cada campo. Quiere print foo,bary también quiere OFS="\t"una salida separada por tabulaciones.
  • Sólo estás mirando el segundo campo, ignorando todos los demás.

Respuesta3

Disculpas por esta frase, pero aquí va:

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

Respuesta4

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

información relacionada