我将不胜感激你的帮助。我正在从数据文件中提取信息,这些文件在某些情况下大小超过 1 TB。
- 每行上的变量由空格分隔。
- 每个文件每行的变量数量是固定的
- 右三列始终为自然数
- 行总是以数组开头
- 数组始终包含每个文件固定数量的元素
- 数组可以包含 1 到 5 个元素
- 源数据文件已正确排序
下面的示例在使用并行时将三元素数组与文件或块中的每个其他数组进行比较。如果数组匹配,则添加右侧第二列,并合并各行。最右边的列和-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
(仅设置输入和输出分隔符)。
如果该键与前一行的键不同,则意味着我们现在正在查看其他一些单词集。输出上一行的key和sum,并重置sum。
对于所有行,将总和增加该行的计数,然后更新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