次のデータがあります。
入力.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