私はこのファイルを持っています:
1 2
2 7
3 4
4 7
5 3
6 7
7 1
8 2
9 4
私が望む出力は
1 13
2 17
3 7
私の入力には9行がありますが、2番目の列に合計を維持しながら3行に減らそうとします。たとえば、最初の列の1は2番目の列の1、2、3、13を表し、最初の行は加算(2 + 4 + 7)を表す式です。どんなアイデアがありますか? awk / perlまたは他のLinuxツールを使用できます。
答え1
解決策は次のとおりですawk
。
awk '{ s+=$2; if (!(NR%3)) { k++; print k,s; s=0 } };
END { if (NR%3) { k++; print k, s } }' file.txt
最初の列を無視してk
出力行番号として生成することをお勧めします。 2番目の列が合計され、s
3行目((NR % 3) == 0
)ごとに出力され、アキュムレータがリセットされます。最後に残りの行がある場合は、残りの合計を出力します。
サンプルファイル出力
1 13
2 17
3 7
完全性のためにここに乾いたモジュロ3とENDブロックで冗長コードを処理する関数を使用するバージョン:
awk 'function outsum() { print ++k,s; s=0 };
{ s+=$2; if (!(NR%3)) { outsum() } };
END { if (NR%3) { outsum() } }' file.txt
答え2
Perlソリューション:
perl -lane '
$s += $F[1];
print(join "\t", ++$l, $s), $s = 0
if 0 == $. % 3 || eof;
' input-file
-n
入力を1行ずつ読みます。-a
空白の各行を @F 配列に分割します。$s
合計を格納する変数として使用されます$.
入力行番号を含む特殊変数です。$l
出力ライン番号です
答え3
これはおそらく行かなければならないと思います。コードゴルフ。これは裏地です。いいえ perl
、awk
またはsed
:
paste <(for i in $(seq 1 0.33333333334 $(A=$(wc -l input.dat | cut -d ' ' -f 1); echo $A/3+1 | bc)); do echo $i/1 | bc; done) <(tr -s ' ' < input.dat | cut -d ' ' -f 3) | datamash -g 1 sum 2
詳細
左
for i in $(seq 1 0.33333333334 $(A=$(wc -l input.dat | cut -d ' ' -f 1); echo $A/3+1 | bc)); do echo $i/1 | bc; done
同様のリストを生成します(入力ファイルの実際の行数について説明します)。
1
1
1
2
2
2
3
3
3
そして右
tr -s ' ' < input.dat | cut -d ' ' -f 3
入力ファイルの最初の列を切り捨て、次のままにします。
2
7
4
7
3
7
1
2
4
paste
それらを再び集めてdatamash
〜これグループ化基準。
答え4
これはシェルコマンド専用のバージョンです。行に分割したが単一行に一緒にスクロールできない理由はありません(そのように始まりました)。
(
s=0 k=1 n=0
while read x v
do
s=$((s+v)) n=$((n+1))
if [[ n -eq 3 ]]
then
echo $k $s
k=$((k+1)) n=0 s=0
fi
done
[[ s -gt 0 ]] && echo $k $s
) <file.txt
( s=0 k=1 n=0; while read x v; do s=$((s+v)) n=$((n+1)); if [[ n -eq 3 ]]; then echo $k $s; k=$((k+1)) n=0 s=0; fi; done; [[ s -gt 0 ]] && echo $k $s ) <file.txt