我有一个这样的数据:
输入.txt
1 0000100101000000
1 0000010100000000
2 1110000001000000
2 1111000000001000
3 0000000111111111
3 1111111100000000
4 8888345500000000
4 0000000000000000
我想对具有相同行号的每两行中的值进行求和:输出:
输出.txt
1 0000110201000000
2 2221000001001000
3 1111111211111111
4 8888345500000000
请问有什么建议吗?我的真实数据有 8000 行,每行 45000 个数字
答案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 或其他),并且数字总是在第二列中,并用空格分隔,那么有一个简单的解决方案:
cut -f2 -d' ' input.txt | perl -Mbigint -nle 'print $_ + <>' > output.txt
该cut
命令仅选择第二列数据,并丢弃第一列。该perl
命令循环遍历传入的行(使用-n
开关)并打印当前行和下一行的总和(因此它以两行为一组工作)。请注意使用该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