awk vergleicht Array mit Array in der vorherigen Zeile

awk vergleicht Array mit Array in der vorherigen Zeile

Ich wäre für Ihre Hilfe dankbar. Ich extrahiere Informationen aus Datendateien, die teilweise über ein Terabyte groß sind.

  • Variablen in jeder Zeile sind durch Leerzeichen getrennt.
  • Die Anzahl der Variablen in jeder Zeile ist für jede Datei festgelegt.
  • Die rechten drei Spalten sind immer natürliche Zahlen
  • Zeilen beginnen immer mit einem Array
  • Arrays enthalten immer eine feste Anzahl von Elementen pro Datei
  • Arrays können 1 bis 5 Elemente enthalten
  • Die Quelldatendatei ist richtig sortiert

Das folgende Beispiel vergleicht bei paralleler Verwendung ein Array mit drei Elementen mit jedem anderen Array in der Datei oder im Block. Wenn das Array übereinstimmt, wird die zweite Spalte von rechts hinzugefügt und die Zeilen werden zusammengeführt. Die Spalte ganz rechts und die Spalte -2 werden gelöscht.

g@grml # zcat googlebooks-eng-us-all-3gram-20120701-zz.gz | head
Z'Z . _END_     1840    1       1
Z'Z . _END_     1847    1       1
Z'Z . _END_     1850    1       1
Z'Z . _END_     1855    1       1
Z'Z . _END_     1856    1       1
Z'Z . _END_     1857    1       1
Z'Z . _END_     1860    1       1
Z'Z . _END_     1863    1       1
Z'Z . _END_     1865    1       1
Z'Z . _END_     1869    1       1



g@grml # zcat googlebooks-eng-us-all-3gram-20120701-zz.gz | parallel -k -q --pipe awk '{a[$1" "$2" "$3] +=$(NF-1)} END{for (i in a) print i, a[i]}' | head 
Zz_NOUN _NOUN_ , 98
zz _._ _PRT_ 120
ZZ or_CONJ _NOUN_ 122
ZZ_NOUN _DET_ _VERB_ 59
zz_DET _NOUN_ . 86
ZZ is_VERB reached 42
ZZ_NUM ^ ^ 65
ZZ _NOUN_ _VERB_ 3163
ZZ ,_. " 52
ZZ / _NUM_ 275

Obwohl das Beispiel ein Array mit 3 Elementen darstellt, arbeite ich mit Arrays, die 1 bis 5 Elemente enthalten.

awk '{a[$1] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2" "$3] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2" "$3" "$4] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2" "$3" "$3" "$5] +=$(NF-1)} END{for (i in a) print i, a[i]}'

Wie weise ich awk an, das aktuelle Array mit dem vorherigen Array in der vorherigen Zeile zu vergleichen, anstatt dass awk versucht, jedes Array mit jedem Array in einer Datei oder einem Block abzugleichen?

Danke

Beispielquelldatei.

wget --show-progress -cq http://storage.googleapis.com/books/ngrams/books/googlebooks-eng-us-all-3gram-20120701-zz.gz -O - | zcat

Antwort1

Die Eingabedaten, die als URL in einem Kommentar angegeben werden, sind tabulatorgetrennt. Das bedeutet, dass wir das erste tabulatorgetrennte Feld als eine Art „Schlüssel“ analysieren können, um es mit anderen Zeilen zu vergleichen. Wir tunnichtSie müssen sich nicht um die durch Leerzeichen getrennten Wörter im ersten Feld kümmern, können aber das gesamte erste Feld als eine einzelne Einheit behandeln.

BEGIN { OFS = FS = "\t" }

{
    count = $(NF - 1)
    key = $1
}

key != previous {
    if (previous != "")
        print previous, sum

    sum = 0
}

{
    sum += count
    previous = key
}

END {
    if (previous != "")
        print previous, sum
}

Dieses awkProgramm analysiert das Feld „Anzahl“ (vorletztes Feld) in countund verwendet dann das erste Feld als „Schlüssel“, um es später mit dem Schlüssel der vorherigen Zeile zu vergleichen. Dies ist der erste Block nach dem BEGINBlock (der nur Eingabe- und Ausgabetrennzeichen festlegt).

Wenn der Schlüssel sich vom Schlüssel in der vorherigen Zeile unterscheidet, bedeutet dies, dass wir uns jetzt einen anderen Satz von Wörtern ansehen. Geben Sie den Schlüssel und die Summe der vorherigen Zeile aus und setzen Sie die Summe zurück.

Erhöhen Sie für alle Zeilen die Summe um die Anzahl dieser Zeile und aktualisieren Sie sie previous(wir sind jetzt mit dieser Zeile fertig, daher ist diese Zeile keydie nächste previous).

Geben Sie am Ende die Informationen für die letzte Zeile der Daten aus.

Sie würden dies mit ausführen awk -f script.awk inputfile.

Als „Einzeiler“:

awk -F '\t' 'BEGIN{OFS=FS} {c=$(NF-1);k=$1} k!=p {if(p!="")print p,s;s=0} {s+=c;p=k} END {if(p!="") print p,s}' file

verwandte Informationen