it-swarm.com.de

Wie erstelle ich eine laufende kumulative Summe der Zahlen in einer Textdatei?

Ich habe eine Textdatei mit 2 Millionen Zeilen. Jede Zeile hat eine positive ganze Zahl. Ich versuche so etwas wie eine Frequenztabelle zu bilden.

Eingabedatei:

3
4
5
8

Die Ausgabe sollte sein:

3
7
12
20

Wie mache ich das?

8
user110327

Mit awk:

awk '{total += $0; $0 = total}1'

$0 ist die aktuelle Zeile. Also füge ich es für jede Zeile der total hinzu, setze die Zeile auf die neue total und dann ist die nachfolgende 1 eine awk-Verknüpfung - sie druckt die aktuelle Zeile für jede true Bedingung und 1 als Bedingung ergibt true.

17
muru

In einem python Skript:

#!/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")

Benutzen

  • Kopieren Sie das Skript in eine leere Datei und speichern Sie es als add_last.py
  • Führen Sie es mit der Quelldatei und der Zieldatei als Argumente aus:

    python3 /path/to/add_last.py <input_file> <output_file>
    

Erläuterung

Der Code ist eher lesbar, aber im Detail:

  • Ausgabedatei zum Schreiben von Ergebnissen öffnen

    with open(out, "wt") as wr:
    
  • Eingabedatei zum Lesen öffnen pro Zeile

    with open(f) as read:
        for l in read:
    
  • Lesen Sie die Zeilen und addieren Sie den Wert der neuen Zeile zur Gesamtsumme:

    n = n + int(l)
    
  • Schreiben Sie das Ergebnis in die Ausgabedatei:

    wr.write(str(n)+"\n")
    
9
Jacob Vlijm

Nur zum Spaß

$ sed 'a+p' file | dc -e0 -
3
7
12
20

Dies funktioniert, indem a+p an jede Zeile der Eingabe angehängt und das Ergebnis dann an den Taschenrechner dc übergeben wird

   +      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.

dann

   p      Prints  the  value on the top of the stack, without altering the
          stack.  A newline is printed after the value.

Das Argument -e0 legt 0 auf den Stapel dc, um die Summe zu initialisieren.

9
steeldriver

In Bash:

#! /bin/bash

file="YOUR_FILE.txt"

TOTAL=0
while IFS= read -r line
do
    TOTAL=$(( TOTAL + line ))
    echo $TOTAL
done <"$file"
8
Julen Larrucea

So drucken Sie Teilsummen von Ganzzahlen, die in der Standardeingabe angegeben sind, eine pro Zeile:

_#!/usr/bin/env python3
import sys

partial_sum = 0
for n in map(int, sys.stdin):
    partial_sum += n
    print(partial_sum)
_

lauffähiges Beispiel .

Wenn der Befehl aus irgendeinem Grund zu langsam ist; Sie könnten das C-Programm verwenden:

_#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;
}
_

Geben Sie zum Erstellen und Ausführen Folgendes ein:

_$ cc cumsum.c -o cumsum
$ ./cumsum < input > output
_

lauffähiges Beispiel .

_UINTMAX_MAX_ ist 18446744073709551615 .

Der C-Code ist um ein Vielfaches schneller als der Befehl awk auf meinem Computer für die Eingabedatei, die generiert wird durch:

_#!/usr/bin/env python3
import numpy.random
print(*numpy.random.random_integers(100, size=2000000), sep='\n')
_
6
jfs

Sie können dies in vim tun. Öffnen Sie die Datei und geben Sie die folgenden Tastatureingaben ein:

[email protected]"<C-a>@[email protected]:wq<cr>

Beachten Sie, dass <C-a> tatsächlich Strg-a ist und <cr>Wagenrücklauf ist, d. H. Die Eingabetaste.

So funktioniert das Zunächst möchten wir das Register 'a' löschen, damit es beim ersten Durchlauf keine Nebenwirkungen hat. Dies ist einfach qaq. Dann machen wir folgendes:

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

Nachdem dieses rekursive Makro ausgeführt wurde, rufen wir einfach :wq<cr> auf, um es zu speichern und zu beenden.

5
DJMcMayhem

Sie möchten wahrscheinlich so etwas:

sort -n <filename> | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'

Erklärung des Befehls:

  • sort -n <filename> | uniq -c sortiert die Eingabe und gibt eine Häufigkeitstabelle zurück
  • | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}' verwandelt den Output in ein schöneres Format

Beispiel:
Eingabedatei list.txt:

4
5
3
4
4
2
3
4
5

Der Befehl:

$ 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
5
Wayne_Yux

Perl Einzeiler:

$ Perl -lne 'print $sum+=$_' input.txt                                                                
3
7
12
20

Bei 2,5 Millionen Zahlenzeilen dauert die Verarbeitung etwa 6,6 Sekunden:

$ 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
5

Ein einfacher Bash-Einzeiler:

x=0 ; while read n ; do x=$((x+n)) ; echo $x ; done < INPUT_FILE

x ist die kumulierte Summe aller Zahlen aus der aktuellen Zeile und darüber.
n ist die Nummer in der aktuellen Zeile.

Wir durchlaufen alle Zeilen n von INPUT_FILE und addieren ihren numerischen Wert zu unserer Variablen x und geben diese Summe während jeder Iteration aus.

Bash ist hier allerdings etwas langsam. Bei einer Datei mit 2 Millionen Einträgen dauert dies ungefähr 20 bis 30 Sekunden, ohne dass die Ausgabe auf der Konsole gedruckt wird (was unabhängig von der von Ihnen verwendeten Methode sogar noch langsamer ist).

3
Byte Commander

Ähnlich wie bei der Antwort von @ steeldriver, jedoch mit dem etwas weniger arkanen bc:

sed 's/.*/a+=&;a/' input | bc

Das Schöne an bc (und dc) ist, dass es sich um willkürliche Präzisionsrechner handelt, die also niemals über die ganzen Zahlen hinauslaufen oder einen Präzisionsmangel erleiden.

Der Ausdruck sed transformiert die Eingabe in:

a+=3;a
a+=4;a
a+=5;a
a+=8;a

Dies wird dann von bc ausgewertet. Die Variable a bc wird automatisch auf 0 initialisiert. Jede Zeile inkrementiert a und gibt sie dann explizit aus.

3
Digital Trauma