テキストファイルのデータの複雑さを減らします。

テキストファイルのデータの複雑さを減らします。

私はこのファイルを持っています:

  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番目の列が合計され、s3行目((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

これはおそらく行かなければならないと思います。コードゴルフ。これは裏地です。いいえ perlawkまたは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

関連情報