
Буду признателен за помощь. Я извлекаю информацию из файлов данных, размер которых в некоторых случаях превышает терабайт.
- Переменные в каждой строке разделены пробелами.
- Количество переменных в каждой строке фиксировано для каждого файла.
- Три правых столбца всегда натуральные числа
- Строки всегда начинаются с массива
- Массивы всегда содержат фиксированное количество элементов на файл.
- Массивы могут содержать от 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