列をシフトした累積合計

列をシフトした累積合計

これは簡単な問題だと確信しているので、あらかじめお詫びします。それでも、やってみます。

cat blah.txt
aa+2
bb+4
cc+10
dd+31

blah.txt を処理して、次のものを生成したいと思います。

aa+0
bb+2
cc+6
dd+16

ここでの考え方は、最初の列が曲のリストであり、2 番目の列が曲の開始時刻である可能性があるということです。

私はこれを awk を使って実行しようと考えました。$1 と累計 $2 を格納する数値インデックスを持つ 2 つの配列を考えました。累計の数値インデックスを 1 ずつシフトするというアイデアでした。

tail -r blah.txt | 
awk -F "+" '{ for(i=0;i<=NR;i++) arr[i+1]+=$2; farr[i]=$1 } END 
{ for(i=NR+1;i>1;i--) {if (i==NR) {print farr[NR] FS 0 } 
else { print farr[i] FS arr[i]}}}'

これは簡潔ではないし、おまけに動作もしない。何よりも配列作成の失敗に困惑しています。

とにかく、もう十分です。誰か親切な人が私をこの苦しみから解放してくれませんか?

トム

答え1

どうぞ:

$ awk -F+ '{sum+=$2;printf("%s+%d\n",$1,sum-$2);}' blah.txt
aa+0
bb+2
cc+6
dd+16

編集1: Sukminderのおかげで、もう少し簡単な方法ができました

$ awk -F+ '{printf("%s+%d\n",$1,sum);sum+=$2}' blah.txt

編集2: もう少し簡潔に、Bernhard に感謝します:

$ awk -F+ '{print $1,sum;sum+=$2}' OFS="+" blah.txt

編集3: しかし、前者では最初の行に 0 が表示されないので、ここでは、トムの質問に回答するためのより短い方法を示す、修正され、やや圧縮されたバージョンを示します (新しいコメントでより良い方法が提案されるまで)。

$ awk -F+ '{print$1,s+0;s+=$2}' OFS=+ blah.txt

答え2

そのための最善の方法は、正規表現を学んで使用することです。そうすれば、将来、そのようなことを行う際に多くのトラブルを回避できます。

cat blah.txt | gawk 'match($0, /([^0-9]*)([0-9]+)/, ary) {print ary[1] ary[2]-2}'

最後の 2 つをシフト変数に置き換える必要があります。 の使用法に注意してくださいgawk。私の知る限り、regular はawk正規表現からグループを抽出できません。

これは何をするのでしょうか?正規表現 を使用してに一致し$0、結果を に入れます。これは、次と一致します: - 0 個以上の数字以外の文字に一致し、それを最初の配列インデックスに配置します (括弧はグループ化と呼ばれる処理を担当します)。次に、長さが 0 以外の数値に一致し (それを配列の 2 番目の要素として配置します)。ary/([^0-9]*)([0-9]+)/([^0-9]*)([0-9]+)

もちろん、エラー チェックやマッチングの特殊なケースなどを追加して、これをさらに複雑にすることもできますが、これ (つまり正規表現) については自分で調べてみることをお勧めします。

関連情報