Linuxで2行ごとに値を合計する方法

Linuxで2行ごとに値を合計する方法

次のデータがあります。

入力.txt

1 0000100101000000
1 0000010100000000
2 1110000001000000
2 1111000000001000
3 0000000111111111
3 1111111100000000
4 8888345500000000
4 0000000000000000

同じ行番号を持つ2行ごとに値を合計したいと思います。出力:

出力.txt

1 0000110201000000
2 2221000001001000
3 1111111211111111
4 8888345500000000

どんな提案がありますか?私の実際のデータには、各行に45000個の数字を持つ8000個の行があります。

答え1

全体的なawkソリューションはどうですか?

awk 'BEGIN { tag = -1; sum = 0}
    {
        if (tag != $1) {
            if (tag > -1) {printf "%d %016d\n",  tag, sum;}
            tag = $1; sum = $2
        } else { sum += $2 }
    }
    END {print tag, sum}'  input.txt

入力が最初の列に基づいてソートされているかどうかはわかりません。次のことができます。次にそれを上記のスクリプトsort -k1.1n input.txtにパイプします。awk

答え2

sed '
    N                                                       #append next line
    s/$/))/                                                 #add `))` to end
    s/\(\S*\s*\)\(.*\)\n\1/printf "%016d\n" \$((10#\2+10#/  #check Nos, form line
    t                                                       #to end if Nos equal
    s/))$//                                                 #remove `))`
    D                                                       #delete 1st line
    ' file |
bash

45000桁の数字に関してbashが処理できる最大の数字は次のとおりです。

/* Minimum and maximum values a `signed long int' can hold.  */
#  if __WORDSIZE == 64
#   define LONG_MAX 9223372036854775807L
#  else
#   define LONG_MAX 2147483647L
#  endif

[1]/usr/include/limits.h

答え3

Rubyはbignumをサポートしているので、次のことができます。

ruby -e '
    sum = Hash.new {|h,k| h[k] = 0} 
    f = File.new(ARGV.shift)
    key, val = f.readline.chomp.split
    width = val.length
    sum[key] = val.to_i
    f.each_line {|line| key,val = line.chomp.split; sum[key] += val.to_i}
    sum.keys.sort.each {|key| printf "%d %0*d\n", key, width, sum[key]}
' file

答え4

追加する行が常に2つあり(3つまたは1つなどではない)、数字が常に2番目の列にスペースで区切られていると仮定できる場合は、簡単な解決策があります。

cut -f2 -d' ' input.txt | perl -Mbigint -nle 'print $_ + <>' > output.txt

このcutコマンドはデータの2番目の列のみを選択し、最初の列は削除します。このperlコマンドは(スイッチを使用して)渡された行を繰り返し、-n現在の行と次の行の合計を印刷します(2つのセットで機能します)。このbigintモジュールを使用すると、長い文字列を非常に大きな数字として扱うことに注意してください。最後に、出力はにリダイレクトされますoutput.txt

出力に番号付きの行が必要な場合は、それをcat -nパイプラインの最後のステップとして追加するか、Perlコードに追加することを検討できます。

cut -f2 -d' ' input.txt | perl -Mbigint -nle 'print ++$x . " " . ($_ + <>)' > output.txt

または、例のように入力形式が空白であると仮定できない場合は、その処理をPerlに移動することもできます。

perl -Mbigint -nle 's/.* //; $x=<>; $x =~ s/.* //; print $_ + $x' input.txt > output.txt

関連情報