テキストのパース
comp.lang.awk ではテキストファイルのパースとなっていますが、実際には面倒な問題です。
3 // Number of blocks five lines of text we don't care about 1 23.5 2 34.2 3 45.1 4 52.4 five lines of text we don't care about 1 24.2 2 27.8 five lines of text 1 26.3 2 34.5 3 45.2 4 52.1 5 36.5
というファイルがある場合に、以下のような出力を得るというものです。
1 (23.5+24.2+26.3)/3 2 (34.2+27.8+34.5)/3 3 (45.4+45.2)/2 4 (52.4+52.1)/2 5 36.5
つまり '$1' が同じもの同士を平均にするというもののようです。
/^=+$/ { block = !block if (!block) { n = asorti(a, copy) for (i = 1; i <= n; i++) { k = gsub(/\+/, "+", a[copy[i]]) + 1 if (k > 1) printf "%d (%s)/%d\n", i, a[copy[i]], k else printf "%d %s\n", i, a[copy[i]] } } print } block && /^[0-9]+ -?[0-9]+(\.[0-9]+)?$/ { if ($1 in a) a[$1] = a[$1] "+" $2 else a[$1] = $2 }
最初のものは asorti() を使って、ソートしつつ $1 が何個あるかを数え上げているものです。
NF == 0 { nline = 0 } # line number within block ++nline > 5 && NF == 2 { counter = $1; value = $2 A[counter] = A[counter] " " value if (counter > maxcounter) maxcounter = counter } END { for (counter = 1; counter <= maxcounter; counter++) { sum = 0 nf = split(A[counter], Arr) for (i = 1; i <= nf; i++) sum += Arr[i] mean = sum/nf printf("%d %.1f\n", counter, mean) } }
awk ' NF==2 { val[$1] = val[$1] sep[$1] $2; sep[$1]="+"; cnt[$1]++; max = ($1 > max ? $1 : max) } END { for (c=1;c<=max;c++) if (c in cnt) if (cnt[c] > 1) printf "%d\t(%s)/%d\n",c,val[c],cnt[c] else printf "%d\t%s\n",c,val[c] }'
/^[0-9]/ && NF==2{ x[$1] = x[$1] " " $2 } END{ for (i in x){ gsub("^ +","",x[i]) # remove the first space y = gsub(" "," + ",x[i]) # add '+' between numbers # choose the format and print data fmt = (y==0)? "%d %s\n" : "%d (%s)/ %d\n" printf fmt,i,x[i],y+1 | "sort -n" # bad idea ? } }
2==NF && /^[0-9]+[ \t]+[0-9.]+$/ { a[$1] += $2 b[$1]++ } END { for (i=1; i in a; i++) print i, a[i] / b[i] }
最後の William James のものは計算してしまっているのですが、出力が複雑なものは計算させた方が楽だったりしますよね。
あとは、以下のようなものもありました。
NF==0 {line=0} ++line>5 && NF>0 { sum[$1] += $2; counter[$1]++; } END { for (i=1; i in sum; ++i) print i, sum[i]/counter[i] }