次のようにタブ区切りのファイル1があります(表示サブセット、実際の行列60x60000)。
rowname header1 header2 header3 header4 header5 header6 header7 header8
rowname1 1 1 10 2 3 1 10 2
rowname2 0 7 200 3 37 1 2 1
次のような別のfile2があります。
header1,header2
header3
header4,header5
header6,header8
header7
file2の各行に指定された列を合計したいと思います。
rowname header1 header3 header4 header6 header7
rowname1 2 10 5 3 10
rowname2 7 200 40 2 2
つまり、1列+列2、3列、4列+5列、6列+8列、7列...
合計する必要がある列もあり、そうでない列もあり、合計する列が常に連続しているわけではありません。
列を合計する場合は、最初の列のヘッダーを出力ファイルに保持する必要があります。
解決策があるかどうか疑問に思うアッ。これまでは、ヘッダー項目を保存する方法だけを知っています。
awk '
NR==1 {
for (i=1; i<=NF; i++) {
f[$i] = i
}
答え1
awk '
FNR==NR{
newhdr[FNR]=$1 # new header name
newhdrcnt++ # number of new header names
for (i=1;i<=NF;i++)
hdrnames[FNR]=$0 # save new header names comma-separated
next
}
FNR==1{
# save column numbers for new header names in array hdrcols
for (i=1;i<=newhdrcnt;i++){
n=split(hdrnames[i], oldhdr, ",")
for(j=1;j<=n;j++){
for(k=2;k<=NF;k++){
if ($(k) == oldhdr[j]){
hdrcols[i]=(j==1 ? "" : hdrcols[i] ",") k;
if (j==n) break
}
}
}
}
# print header
printf $1
for (i=1;i<=newhdrcnt;i++)
printf FS newhdr[i]
printf ORS
next
}
{ # print data
printf $1
for (i=1;i<=newhdrcnt;i++){
n=split(hdrcols[i], cols, ",")
res=0
for(j=1;j<=n;j++)
res=res+$(cols[j])
printf FS res
}
printf ORS
}
' FS="," file2 FS="\t" file1
出力:
rowname header1 header3 header4 header6 header7
rowname1 2 10 5 3 10
rowname2 7 200 40 2 2
答え2
脳を傷つけたようだがgawk
#!/usr/bin/awk -f
BEGIN{FS="\t"}
NR==FNR{H[NR]=","$0","; next}
FNR==1{for (i=2;i<=NF; i++) T[i]=","$i","; printf $1;
for (i=1; i<=length(H); i++){split(H[i],sp,","); printf "\t"sp[2]}; print ""}
FNR>1{delete S; for (i=2; i<=NF; i++)
{for (h in H) {if (H[h] ~ T[i]) S[h]+=$i}} printf $1;
for (i=1; i<=length(H); i++) printf "\t"S[i]; print""}
次のように呼び出されます
./script file2 file1 | column -t
出力
rowname header1 header3 header4 header6 header7
rowname1 2 10 5 3 10
rowname2 7 200 40 2 2
@freddyに対する@paul_pedantのコメントに基づいて、指定されていない列は削除されます。
牙
設定FS
BEGIN{FS="\t"}
要件と列のリストを配列にロードし、各末尾にH[]
「、」を追加します(以降、正規表現の不一致を防ぐため)。
NR==FNR{H[NR]=","$0","; next}
データファイルの最初の行である場合は、配列に列ヘッダーをロードし、T[]
ヘッダー名の各末尾に「、」を追加します。$i
FNR==1{for (i=2;i<=NF; i++) T[i]=","$i",";
...抽出されたタイトルを、指定された文字列の最初の部分の合計として印刷します。
printf $1; for (i=1; i<=length(H); i++){split(H[i],sp,","); printf "\t"sp[2]}; print ""}
各データ行に対して合計配列を消去し、フィールドを繰り返しますS[]
。
FNR>1{delete S; for (i=2; i<=NF; i++)
各H[]
フィールド名を確認しT[]
、存在する場合は、一致にインデックス付けされた合計配列にフィールド値を追加します。S[h]
{for (h in H) {if (H[h] ~ T[i]) S[h]+=$i}}
各行の終わりに印刷
printf $1; for (i=1; i<=length(H); i++) printf "\t"S[i]; print""}