Mehrere Zeilen in derselben Datei basierend auf Spalte 1 zusammenführen

Mehrere Zeilen in derselben Datei basierend auf Spalte 1 zusammenführen

Ich lerne noch Programmieren und habe schon vieles ausprobiert, aber ich bekomme einfach nicht das richtige Format hin. Ich habe eineTabulatorgetrenntDatei mit 17 Spalten und vielen (ca. 50.000) Zeilen. Die Datei ist bereits nach der ersten Spalte sortiert. Ich möchte Zeilen zusammenführen, die die gleiche erste Spalte (A) haben, aber alle anderen 16 Spalten sind unterschiedlich und ich möchte alle Informationen in einer Zeile behalten, vorzugsweise in der gleichen Spalte mitSemikolon ;als Trennzeichen zwischen ihnen. Ich möchte Tabulatoren als Trennzeichen in der Ausgabedatei beibehalten. Vielen Dank für die Antworten und wenn Sie auch die Antwort erklären könnten, wo ich einen Fehler gemacht habe, wäre das noch besser :).

Ich habe bisher versucht:

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

DATEIFORMAT (die anderen 15 Spalten haben das gleiche Format wie Spalte B)

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

Die Ausgabe, die ich möchte (ich brauche alle 17 Spalten und für die Spalten 2-16 brauche ich dieselbe Ausgabe wie in Spalte B und C). Alle Fälle von B sollten unter B stehen und alle Fälle von C sollten unter C stehen und alle Fälle von D sollten unter D stehen usw. Die Ausgabe hat also genau wie die Eingabe 17 Spalten und statt 50.000 Zeilen sollte sie jetzt etwa 20.000 haben, da es viele Wiederholungen für Spalte 1 gibt (für diese bestimmte Datei):

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

Antwort1

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

Antwort2

Eine Perl-Lösung:

$ 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

Dies kann mit einer beliebigen Anzahl von Feldern funktionieren. Allerdings müssen dazu einige Dinge in den Speicher geladen werden, was bei großen Dateien ein Problem darstellen kann.


Was Ihren Fehler angeht, können wir Ihnen das nicht sagen, sofern Sie nicht erklären, was tatsächlich passiert ist. Aber spontan fällt mir ein, dass Ihr Perl-Versuch aus folgendem Grund fehlschlagen würde:

  • Sie verwenden -F,, wodurch der Feldtrenner auf ein Komma gesetzt wird, wenn Ihre Eingabe Tabulatoren enthält.
  • Sie verwenden -lund print "foo\n". Das -lfügt bereits jedem Druckaufruf eine neue Zeile hinzu, sodass Sie mehrere leere Zeilen haben.
  • Sie verwenden $h{$F[0]}.", ".$F[1];zum Anhängen, sodass Sie beim ersten Ausführen, wenn es nicht definiert ist, am Anfang Ihres gespeicherten Werts $h{$F[0]}ein zusätzliches Element hinzufügen .,
  • Sie betrachten nur das zweite Feld und ignorieren alle anderen.

Ebenso awkwird Ihr Versuch scheitern, weil:

  • Sie drucken foo""bar, wodurch die Ausgabe ohne Leerzeichen zwischen den einzelnen Feldern aneinandergereiht wird. Sie möchten print foo,barund Sie möchten auch OFS="\t"eine tabulatorgetrennte Ausgabe.
  • Sie betrachten nur das zweite Feld und ignorieren alle anderen.

Antwort3

entschuldigen Sie diesen Einzeiler, aber hier ist er -

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

Antwort4

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

verwandte Informationen