降低文本文件中数据的复杂性

降低文本文件中数据的复杂性

我有这个文件:

  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 行,我想将其减少到三行,同时保留第二列的总量。例如,第一列中的 1 代表第二列中的 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输出行号。第二列在 中求和s,并且每三行 ( (NR % 3) == 0) 输出它并重置累加器。最后,如果我们有任何剩余的行,我们将输出剩余的总和。

示例文件的输出

1 13
2 17
3 7

只是为了完整起见,这里有一个干燥使用函数处理 modulo-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逐行读取输入
  • -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

这是仅使用 shell 命令的版本。我把它分成几行,但你没有理由不能把它作为一行行一起滚动(这就是它的开始方式):

(
    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

相关内容