Wie ordne ich Elemente einer Überschrift zu?

Wie ordne ich Elemente einer Überschrift zu?

Ich habe über 5000 durch Leerzeichen getrennte Zeilen wie unten:

Item_A: Acou#1  Bla#5

Item_B: Acou#1  Elfa#2  Flq#2

Item_C: Acou#1  Bla#4   Elfa#2  Flq#2

Item_D: Agly#3  Bla#4   Elfa#2

Ich möchte eine Tabelle mit gemeinsamen Überschriften für alle und jeweils einer Menge in einer Tabelle wie unten erstellen,

             Acou  Agly  Bla  Elfa  Flq

Item_A:      1     0     5    0     0

Item_B:      1     0     0    2     2

Item_C:      1     0     4    2     2

Item_D:      0     3     4    2     0

Ich habe Zeilen mit „Acou“, dann „Bla“ usw. durchsucht. Anschließend habe ich sie in Excel bearbeitet, um sie zu quantifizieren und alle einzelnen Dateien zu einer Datei zusammenzufügen. Das hat jedoch viel Zeit in Anspruch genommen.

Antwort1

BEGIN { OFS = "\t" }

# Collect headers from data
FNR == NR {
    for (i = 2; i <= NF; ++i)
        if (!($i in heads))
            heads[$i]
    next
}

# Output header
FNR == 1 {
    line = "Items"
    for (j in heads)
        line = line OFS j
    print line
}

{
    line = $1
    # Iterate through the header items, testing each field against it
    for (j in heads) {
        found = 0 # assume not found
        for (i = 2; !found && i <= NF; ++i)
            if ($i == j)
                found = 1 # matches header
        line = line OFS found
    }
    print line
}

Ausführen des folgenden Vorgangs auf Ihren Daten (nachdem Sie leere Zeilen entfernt haben):

$ awk -f script.awk file file
Items   Acou#1  Bla#4   Bla#5   Elfa#2  Agly#3  Flq#2
Item_A: 1       0       1       0       0       0
Item_B: 1       0       0       1       0       1
Item_C: 1       1       0       1       0       1
Item_D: 0       1       0       1       1       0

Beachten Sie, dass Sie die Eingabedatendatei zweimal angeben müssen. Dies liegt daran, dass wir sie zweimal scannen. Beim ersten Scan sammeln wir die Datenelemente in jeder Zeile (dem FNR == NRBlock). Beim zweiten Scan testen wir jedes gesammelte Datenelement (die Header) anhand der Daten in jeder Zeile.

Die Ausgabe erfolgt einfach, 0wenn das Feld im Header in den Daten in dieser Zeile nicht vorhanden ist und 1wenn es vorhanden ist. Dies ist nichtganzwas du verlangt hast, also …

Eine Variante, die die Überschriften am abschneidet und den Teil nach dem als anzuzeigende Daten #verwendet :#

BEGIN { OFS = "\t" }

# Collect headers from data
FNR == NR {
    for (i = 2; i <= NF; ++i) {
        split($i, h, "#")
        if (!(h[1] in heads))
            heads[h[1]]
    }
    next
}

# Output header
FNR == 1 {
    line = "Items"
    for (j in heads)
        line = line OFS j
    print line
}

{
    line = $1
    # Iterate through the header items, testing each field against it
    for (j in heads) {
        found = 0 # assume not found
        for (i = 2; !found && i <= NF; ++i) {
            split($i, h, "#")
            if (h[1] == j)
                found = h[2] # matches header
        }
        line = line OFS found
    }
    print line
}

Ausführen:

$ awk -f script.awk file file
Items   Elfa    Bla     Acou    Agly    Flq
Item_A: 0       5       1       0       0
Item_B: 2       0       1       0       2
Item_C: 2       4       1       0       2
Item_D: 2       4       0       3       0

Beachten Sie, dass die Reihenfolge der Spalten nicht unbedingt sortiert ist (da sie als Schlüssel in einem assoziativen Array gespeichert sind). Ich überlasse es dem Leser, sie zu sortieren.

Antwort2

Wenn es Ihnen nichts ausmacht,GNU Datamashin die Mischung, dann könnten Sie die Einträge einfach serialisieren und sie dann in einer Kreuztabelle darstellen:

awk '
  {for (i=2;i<=NF;i++) {split($i,a,"#"); print $1,a[1],a[2]}}' OFS='\t' file | 
  datamash --filler=0 crosstab 1,2 count 3
    Acou    Agly    Bla Elfa    Flq
Item_A: 1   0   1   0   0
Item_B: 1   0   0   1   1
Item_C: 1   0   1   1   1
Item_D: 0   1   1   1   0

Alternativ mit GNU awk (das mehrdimensionale Arrays zulässt):

gawk '
  BEGIN {
    OFS="\t";
    PROCINFO["sorted_in"] = "@ind_str_asc";
  }
  {
    for (i=2;i<=NF;i++) {
      split($i,a,"#"); 
      h[a[1]] = 1;
      t[$1][a[1]] += a[2];
    }
  } 
  END {
    for (j in h) printf("\t%s", j);
    printf "\n";
    for (i in t) {
      printf("%s",i);
      for (j in h) 
        printf("\t%d", j in t[i] ? t[i][j] : 0);
      printf "\n";
    }
  }' file
    Acou    Agly    Bla Elfa    Flq
Item_A: 1   0   5   0   0
Item_B: 1   0   0   2   2
Item_C: 1   0   4   2   2
Item_D: 0   3   4   2   0

verwandte Informationen