awk сравнивает массив с массивом на предыдущей строке

awk сравнивает массив с массивом на предыдущей строке

Буду признателен за помощь. Я извлекаю информацию из файлов данных, размер которых в некоторых случаях превышает терабайт.

  • Переменные в каждой строке разделены пробелами.
  • Количество переменных в каждой строке фиксировано для каждого файла.
  • Три правых столбца всегда натуральные числа
  • Строки всегда начинаются с массива
  • Массивы всегда содержат фиксированное количество элементов на файл.
  • Массивы могут содержать от 1 до 5 элементов.
  • Исходный файл данных правильно отсортирован

Пример ниже сравнивает массив из трех элементов с каждым другим массивом в файле или фрагменте при использовании parallel. Если массив совпадает, добавляется второй столбец справа, а строки объединяются. Самый правый столбец и столбец -2 очищаются.

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

Хотя в примере представлен массив из 3 элементов, я работаю с массивами, содержащими от 1 до 5 элементов.

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

Как мне заставить awk сравнивать текущий массив с предыдущим массивом в предыдущей строке, вместо того чтобы заставлять awk пытаться сопоставить каждый массив с каждым массивом в файле или фрагменте?

Спасибо

Пример исходного файла.

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

решение1

Входные данные, указанные как URL в комментарии, разделены табуляцией. Это означает, что мы можем проанализировать его первое поле, разделенное табуляцией, как своего рода «ключ» для сравнения с другими строками. Мы делаемнетнеобходимо учитывать слова, разделенные пробелами в первом поле, но можно обрабатывать все первое поле как единое целое.

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
}

Эта awkпрограмма разбирает поле "count" (предпоследнее поле) в count, затем использует первое поле как "ключ" для последующего сравнения с ключом предыдущей строки. Это первый блок после блока BEGIN(который просто устанавливает разделители ввода и вывода).

Если ключ отличается от ключа в предыдущей строке, это означает, что мы сейчас смотрим на какой-то другой набор слов. Выведите ключ и сумму предыдущей строки и сбросьте сумму.

Для всех строк увеличиваем сумму на число из этой строки и обновляем previous(теперь мы закончили с этой строкой, поэтому ее значение keyравно значению следующей previous).

В конце выведите информацию для последней строки данных.

Вы можете запустить это с помощью awk -f script.awk inputfile.

В качестве «однострочника»:

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

Связанный контент