1116 Stimmen

Shell-Befehl zum Summieren ganzer Zahlen, eine pro Zeile?

Ich bin auf der Suche nach einem Befehl, der (als Eingabe) mehrere Textzeilen akzeptiert, wobei jede Zeile eine einzelne Ganzzahl enthält, und die Summe dieser Ganzzahlen ausgibt.

Als Hintergrundinformation habe ich eine Protokolldatei, die Zeitmessungen enthält. Durch Suchen nach den relevanten Zeilen und ein wenig sed Umformatierung kann ich alle Zeitangaben in dieser Datei auflisten. Ich möchte die Gesamtsumme ausrechnen. Ich kann diese Zwischenausgabe an einen beliebigen Befehl weiterleiten, um die Endsumme zu bilden. Ich habe immer verwendet expr in der Vergangenheit, aber solange es nicht im RPN-Modus läuft, glaube ich nicht, dass es damit zurechtkommt (und selbst dann wäre es schwierig).

Wie kann ich die Summe ganzer Zahlen ermitteln?

98voto

Giacomo Punkte 10677

Einfaches Bash:

$ cat numbers.txt 
1
2
3
4
5
6
7
8
9
10
$ sum=0; while read num; do ((sum += num)); done < numbers.txt; echo $sum
55

72voto

CB Bailey Punkte 693084
dc -f infile -e '[+z1<r]srz1<rp'

Beachten Sie, dass negative Zahlen mit vorangestelltem Minuszeichen für dc da es die _ Präfix und nicht - Präfix dafür. Zum Beispiel, über tr '-' '_' | dc -f- -e '...' .

Edit: Da diese Antwort so viele Stimmen "für Unklarheit" bekommen hat, hier eine ausführliche Erklärung:

Der Ausdruck [+z1<r]srz1<rp macht folgendes :

[   interpret everything to the next ] as a string
  +   push two values off the stack, add them and push the result
  z   push the current stack depth
  1   push one
  <r  pop two values and execute register r if the original top-of-stack (1)
      is smaller
]   end of the string, will push the whole thing to the stack
sr  pop a value (the string above) and store it in register r
z   push the current stack depth again
1   push 1
<r  pop two values and execute register r if the original top-of-stack (1)
    is smaller
p   print the current top-of-stack

Als Pseudocode:

  1. Definieren Sie "add_top_of_stack" als:
    1. Entfernen Sie die beiden obersten Werte vom Stapel und fügen Sie das Ergebnis wieder hinzu
    2. Wenn der Stapel zwei oder mehr Werte enthält, führen Sie "add_top_of_stack" rekursiv aus
  2. Wenn der Stapel zwei oder mehr Werte enthält, führen Sie "add_top_of_stack" aus.
  3. Drucken Sie das Ergebnis aus, das nun als einziges Element auf dem Stapel verbleibt.

Um die Einfachheit und Kraft von dc Hier ist ein funktionierendes Python-Skript, das einige der Befehle aus dc und führt eine Python-Version des obigen Befehls aus:

### Implement some commands from dc
registers = {'r': None}
stack = []
def add():
    stack.append(stack.pop() + stack.pop())
def z():
    stack.append(len(stack))
def less(reg):
    if stack.pop() < stack.pop():
        registers[reg]()
def store(reg):
    registers[reg] = stack.pop()
def p():
    print stack[-1]

### Python version of the dc command above

# The equivalent to -f: read a file and push every line to the stack
import fileinput
for line in fileinput.input():
    stack.append(int(line.strip()))

def cmd():
    add()
    z()
    stack.append(1)
    less('r')

stack.append(cmd)
store('r')
z()
stack.append(1)
less('r')
p()

53voto

Daniel Punkte 81

Reiner und kurzer Bash.

f=$(cat numbers.txt)
echo $(( ${f//$'\n'/+} ))

45voto

j_random_hacker Punkte 49159
perl -lne '$x += $_; END { print $x; }' < infile.txt

41voto

Alfe Punkte 51658

Ich habe einen schnellen Benchmark der vorhandenen Antworten durchgeführt, der

  • nur Standardwerkzeuge verwenden (Entschuldigung für Dinge wie lua o rocket ),
  • sind echte Einzeiler,
  • sind in der Lage, riesige Zahlenmengen zu addieren (100 Millionen), und
  • schnell sind (die, die länger als eine Minute dauern, habe ich ignoriert).

Ich habe immer die Zahlen von 1 bis 100 Millionen addiert, was auf meinem Rechner in weniger als einer Minute für mehrere Lösungen machbar war.

Hier sind die Ergebnisse:

Python

:; seq 100000000 | python -c 'import sys; print sum(map(int, sys.stdin))'
5000000050000000
# 30s
:; seq 100000000 | python -c 'import sys; print sum(int(s) for s in sys.stdin)'
5000000050000000
# 38s
:; seq 100000000 | python3 -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 27s
:; seq 100000000 | python3 -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 22s
:; seq 100000000 | pypy -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 11s
:; seq 100000000 | pypy -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 11s

Awk

:; seq 100000000 | awk '{s+=$1} END {print s}'
5000000050000000
# 22s

Paste & Bc

Auf meinem Rechner ging der Speicherplatz aus. Es funktionierte für die halbe Größe der Eingabe (50 Millionen Zahlen):

:; seq 50000000 | paste -s -d+ - | bc
1250000025000000
# 17s
:; seq 50000001 100000000 | paste -s -d+ - | bc
3750000025000000
# 18s

Ich schätze also, dass es für die 100 Millionen Nummern ~35s gebraucht hätte.

Perl

:; seq 100000000 | perl -lne '$x += $_; END { print $x; }'
5000000050000000
# 15s
:; seq 100000000 | perl -e 'map {$x += $_} <> and print $x'
5000000050000000
# 48s

Rubinrot

:; seq 100000000 | ruby -e "puts ARGF.map(&:to_i).inject(&:+)"
5000000050000000
# 30s

C

Nur zum Vergleich habe ich die C-Version kompiliert und auch diese getestet, um eine Vorstellung davon zu bekommen, wie viel langsamer die toolbasierten Lösungen sind.

#include <stdio.h>
int main(int argc, char** argv) {
    long sum = 0;
    long i = 0;
    while(scanf("%ld", &i) == 1) {
        sum = sum + i;
    }
    printf("%ld\n", sum);
    return 0;
}

:; seq 100000000 | ./a.out 
5000000050000000
# 8s

Schlussfolgerung

C ist natürlich am schnellsten mit 8s, aber die Pypy-Lösung fügt nur einen sehr geringen Overhead von etwa 30% zu 11s hinzu . Aber, um fair zu sein, Pypy ist nicht gerade Standard. Die meisten Leute haben nur CPython installiert, das deutlich langsamer ist (22s), genau so schnell wie die beliebte Awk-Lösung.

Die schnellste Lösung auf der Grundlage von Standardwerkzeugen ist Perl (15s).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X