如何在Linux中对每两行的值求和

如何在Linux中对每两行的值求和

我有一个这样的数据:

输入.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

相关内容