如何生成文本文件中数字的运行累积总数?

9 command-line text-processing

我有一个 200 万行的文本文件。每行都有一个正整数。我正在尝试形成频率表之类的东西。

输入文件:

3
4
5
8
Run Code Online (Sandbox Code Playgroud)

输出应该是:

3
7
12
20
Run Code Online (Sandbox Code Playgroud)

我该怎么做?

mur*_*uru 20

awk

awk '{total += $0; $0 = total}1'
Run Code Online (Sandbox Code Playgroud)

$0是当前行。因此,对于每一行,我将其添加到total,将该行设置为 new total,然后尾随1是一个 awk 快捷方式 - 它为每个真条件打印当前行,并且1当条件评估为真时。

  • 编写 awk 脚本的一种更短且可能更容易理解的方法是 `{print(total += $0)}` (10认同)

Jac*_*ijm 9

在 python 脚本中:

#!/usr/bin/env python3
import sys

f = sys.argv[1]; out = sys.argv[2]

n = 0

with open(out, "wt") as wr:
    with open(f) as read:
        for l in read:
            n = n + int(l); wr.write(str(n)+"\n")
Run Code Online (Sandbox Code Playgroud)

使用

  • 将脚本复制到一个空文件中,另存为 add_last.py
  • 使用源文件和目标输出文件作为参数运行它:

    python3 /path/to/add_last.py <input_file> <output_file>
    
    Run Code Online (Sandbox Code Playgroud)

解释

代码相当可读,但详细说明:

  • @JFSebastian 如果更惯用的版本更慢,为什么会有人喜欢它?“pythonic”并没有什么特别之处,它只是一种约定,可以帮助 python 开发人员共享代码和可读性标准。如果更惯用的版本效率较低(较慢),则不应使用它,除非您在标准化比性能更重要的环境中工作(这对我来说听起来很糟糕)。 (8认同)
  • @muru 当然可以,但这完全可读。唯一的犯罪不是“pythonic”。更不用说我们谈论的是 7 行代码,而不是某个大型项目。以风格约定的名义牺牲效率似乎是错误的方法。 (4认同)
  • 这与短小或时间性能无关(百万行不是大数据)。您答案中的代码不是惯用的 Python。[我的回答](http://askubuntu.com/a/879196/3712) 只是你的 Pythonic 版本。 (3认同)
  • 【代码可以简化】(http://askubuntu.com/a/879196/3712) (2认同)
  • @terdon 关于过早优化有些话要说。由于长期可维护性,可读性可能很重要。 (2认同)

ste*_*ver 9

只是为了好玩

$ sed 'a+p' file | dc -e0 -
3
7
12
20
Run Code Online (Sandbox Code Playgroud)

这是通过一个ppending+p到输入的各行,然后传递结果给dc计算器,其中

   +      Pops two values off the stack, adds them, and pushes the result.
          The precision of the result is determined only by the values  of
          the arguments, and is enough to be exact.
Run Code Online (Sandbox Code Playgroud)

然后

   p      Prints  the  value on the top of the stack, without altering the
          stack.  A newline is printed after the value.
Run Code Online (Sandbox Code Playgroud)

-e0参数推0dc堆栈初始化的总和。


Jul*_*cea 8

在 Bash 中:

#! /bin/bash

file="YOUR_FILE.txt"

TOTAL=0
while IFS= read -r line
do
    TOTAL=$(( TOTAL + line ))
    echo $TOTAL
done <"$file"
Run Code Online (Sandbox Code Playgroud)


jfs*_*jfs 6

要打印标准输入上给出的整数的部分和,每行一个:

#!/usr/bin/env python3
import sys

partial_sum = 0
for n in map(int, sys.stdin):
    partial_sum += n
    print(partial_sum)
Run Code Online (Sandbox Code Playgroud)

可运行示例

如果由于某种原因命令太慢;你可以使用 C 程序:

#include <stdint.h>
#include <ctype.h>
#include <stdio.h>

int main(void)
{
  uintmax_t cumsum = 0, n = 0;
  for (int c = EOF; (c = getchar()) != EOF; ) {
    if (isdigit(c))
      n = n * 10 + (c - '0');
    else if (n) { // complete number
      cumsum += n;
      printf("%ju\n", cumsum);
      n = 0;
    }
  }
  if (n)
    printf("%ju\n", cumsum + n);
  return feof(stdin) ? 0 : 1;
}
Run Code Online (Sandbox Code Playgroud)

要构建并运行它,请键入:

$ cc cumsum.c -o cumsum
$ ./cumsum < input > output
Run Code Online (Sandbox Code Playgroud)

可运行示例

UINTMAX_MAX18446744073709551615

对于由以下生成的输入文件,C 代码比我机器上的 awk 命令快几倍:

$ cc cumsum.c -o cumsum
$ ./cumsum < input > output
Run Code Online (Sandbox Code Playgroud)

  • 可能还值得一提的是 [`accumulate()` itertool](https://docs.python.org/3/library/itertools.html#itertools.accumulate) (2认同)

Way*_*Yux 5

你可能想要这样的东西:

sort -n <filename> | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
Run Code Online (Sandbox Code Playgroud)

命令的解释:

  • sort -n <filename> | uniq -c 对输入进行排序并返回一个频率表
  • | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}' 将 ooutput 变成更好的格式

示例:
输入文件list.txt

4
5
3
4
4
2
3
4
5
Run Code Online (Sandbox Code Playgroud)

命令:

$ sort -n list.txt | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
Number  Frequency
2   1
3   2
4   4
5   2
Run Code Online (Sandbox Code Playgroud)


小智 5

你可以在 vim 中做到这一点。打开文件并键入以下按键:

qaqqayiwj@"<C-a>@aq@a:wq<cr>
Run Code Online (Sandbox Code Playgroud)

请注意,<C-a>实际上是 ctrl-a,并且<cr>回车,即回车按钮。

这是它的工作原理。首先,我们要清除寄存器“a”,以便它在第一次通过时没有副作用。这简直了qaq。然后我们执行以下操作:

qa                  " Start recording keystrokes into register 'a'
  yiw               " Yank this current number
     j              " Move down one line. This will break the loop on the last line
      @"            " Run the number we yanked as if it was typed, and then
        <C-a>       " increment the number under the cursor *n* times
             @a     " Call macro 'a'. While recording this will do nothing
               q    " Stop recording
                @a  " Call macro 'a', which will call itself creating a loop
Run Code Online (Sandbox Code Playgroud)

在这个递归宏运行完成后,我们只需调用:wq<cr>保存并退出。


Ser*_*nyy 5

Perl 单行:

$ perl -lne 'print $sum+=$_' input.txt                                                                
3
7
12
20
Run Code Online (Sandbox Code Playgroud)

有 250 万行数字,处理大约需要 6.6 秒:

$ time perl -lne 'print $sum+=$_' large_input.txt > output.txt                                        
    0m06.64s real     0m05.42s user     0m00.09s system

$ wc -l large_input.txt
2500000 large_input.txt
Run Code Online (Sandbox Code Playgroud)