Ich habe eine Datei, die mehrere tausend Zahlen enthält, jede in einer eigenen Zeile:
34
42
11
6
2
99
...
Ich möchte ein Skript schreiben, das die Summe aller Zahlen in der Datei druckt. Ich habe eine Lösung, aber sie ist nicht sehr effizient. (Die Ausführung dauert einige Minuten.) Ich suche nach einer effizienteren Lösung. Irgendwelche Vorschläge?
awk
und verwendenbc
). Diese alle haben in weniger als 10 Sekunden eine Million Zahlen addiert. Schauen Sie sich diese an und sehen Sie, wie es in reiner Schale gemacht werden kann.Antworten:
Für einen Perl-Einzeiler ist es im Grunde dasselbe wie die
awk
Lösung in Ayman Houriehs Antwort :Wenn Sie neugierig sind, was Perl-Einzeiler tun, können Sie sie trennen:
Das Ergebnis ist eine ausführlichere Version des Programms in einer Form, die niemand alleine schreiben würde:
Nur zum Kichern habe ich dies mit einer Datei versucht, die 1.000.000 Zahlen enthält (im Bereich von 0 bis 9.999). Auf meinem Mac Pro kehrt es praktisch sofort zurück. Das ist schade, denn ich hatte gehofft, dass die Verwendung
mmap
sehr schnell sein würde, aber es ist genau die gleiche Zeit:quelle
while { }
Schleife um Ihr Programm hinzu. Wenn Sie} ... {
hineinstecken, dann haben Siewhile { } ... { }
. Böse? Leicht.-MO=Deparse
Option! Obwohl zu einem anderen Thema.Sie können awk verwenden:
quelle
-F '\t'
Option, wenn Ihre Felder Leerzeichen enthalten und durch Tabulatoren getrennt sind.Keine der bisher verwendeten Lösungen
paste
. Hier ist eine:Berechnen Sie als Beispiel Σn, wobei 1 <= n <= 100000:
(Für Neugierige
seq n
würde eine Folge von Zahlen von1
bis zun
einer positiven Zahl gedrucktn
.)quelle
seq 100000 | paste -sd+ - | bc -l
unter Mac OS X Bash Shell. Und das ist bei weitem die süßeste und unixeste Lösung!Lassen Sie es uns zum Spaß vergleichen:
Ich habe den Sed-Lauf nach 5 Minuten abgebrochen
Ich habe getaucht luaund es ist schnell:
und während ich das aktualisiere, Ruby:
Beachten Sie den Rat von Ed Morton: Verwenden
$1
vs mit
$0
quelle
tr
Lösung sein.$0
anstelle von verwenden,$1
da awk die Feldaufteilung durchführt (was offensichtlich Zeit kostet), wenn ein Feld im Skript speziell erwähnt wird, dies jedoch nicht anders ist.Eine andere Option ist
jq
:-s
(--slurp
) liest die Eingabezeilen in ein Array.quelle
Das ist gerade Bash:
quelle
Hier ist ein weiterer Einzeiler
Dies setzt voraus, dass die Zahlen ganze Zahlen sind. Wenn Sie Dezimalstellen benötigen, versuchen Sie es
Stellen Sie 2 auf die Anzahl der benötigten Dezimalstellen ein.
quelle
Ich bevorzuge die Verwendung von GNU-Datamash für solche Aufgaben, da es prägnanter und lesbarer ist als Perl oder Awk. Beispielsweise
wobei 1 die erste Datenspalte bezeichnet.
quelle
quelle
Ich bevorzuge es, R dafür zu verwenden:
quelle
(wie brian d foys antwort, ohne 'END')
quelle
perl -MO=Deparse
zu sehen, wie Perl das Programm analysiert. oder die Dokumente für perlrun: perldoc.perl.org/perlrun.html (Suche nach -n). Perl umschließt Ihren Code mit {}, wenn Sie -n verwenden, damit er zu einem vollständigen Programm wird.Prägnanter:
quelle
time python -c "print(sum([float(s) for s in open('random_numbers','r')]))"
Perl 6
quelle
Nur zum Spaß, machen wir es mit PDL , Perls Array-Mathe-Engine!
rcols
liest Spalten in eine Matrix (in diesem Fall 1D) undsum
summiert (überraschend) das gesamte Element der Matrix.quelle
Hier ist eine Lösung mit Python mit einem Generatorausdruck. Getestet mit einer Million Nummern auf meinem alten, groben Laptop.
quelle
map()
map(float, sys.stdin)
Ich konnte nicht einfach vorbeikommen ... Hier ist mein Haskell Einzeiler. Es ist eigentlich gut lesbar:
Leider gibt es keine Möglichkeit, es
ghci -e
einfach auszuführen, daher benötigt es die Hauptfunktion, Drucken und Kompilieren.Zur Verdeutlichung lesen wir die gesamte Eingabe (
getContents
), teilen sie durchlines
,read
als Zahlen undsum
.<$>
istfmap
Operator - wir verwenden ihn anstelle der üblichen Funktionsanwendung, da dies alles sicher in IO geschieht.read
braucht eine zusätzlichefmap
, da es auch in der Liste ist.Hier ist ein seltsames Upgrade, damit es mit Floats funktioniert:
quelle
quelle
Ausführen von R-Skripten
Ich habe ein R-Skript geschrieben, um Argumente eines Dateinamens zu übernehmen und die Zeilen zu summieren.
Dies kann mit dem Paket "data.table" oder "vroom" wie folgt beschleunigt werden:
Benchmarking
Gleiche Benchmarking-Daten wie @glenn jackman .
Im Vergleich zum obigen R-Aufruf ist das Ausführen von R 3.5.0 als Skript mit anderen Methoden vergleichbar (auf demselben Linux-Debian-Server).
R-Skript mit readLines
R-Skript mit data.table
R-Skript mit vroom
Vergleich mit anderen Sprachen
Als Referenz hier einige andere Methoden, die auf derselben Hardware vorgeschlagen wurden
Python 2 (2.7.13)
Python 3 (3.6.8)
Ruby (2.3.3)
Perl (5.24.1)
Awk (4.1.4)
C (Clang-Version 3.3; gcc (Debian 6.3.0-18) 6.3.0)
Update mit weiteren Sprachen
Lua (5.3.5)
tr (8.26) muss in bash zeitgesteuert sein und ist nicht mit zsh kompatibel
sed (4.4) muss in bash zeitgesteuert sein und ist nicht mit zsh kompatibel
Hinweis: sed-Aufrufe scheinen auf Systemen mit mehr verfügbarem Speicher schneller zu funktionieren (beachten Sie kleinere Datensätze, die für das Benchmarking von sed verwendet werden).
Julia (0,5,0)
Beachten Sie, dass Datei-E / A-Methoden wie in R eine unterschiedliche Leistung aufweisen.
quelle
C ++ "Einzeiler":
quelle
Ein anderer zum Spaß
oder nur eine andere Bash
Aber awk Lösung ist wahrscheinlich am besten, da es am kompaktesten ist.
quelle
C gewinnt immer für Geschwindigkeit:
Timing für 1M-Nummern (gleiche Maschine / Eingabe wie meine Python-Antwort):
quelle
Mit Ruby:
quelle
ruby -e'p readlines.map(&:to_f).reduce(:+)'
.Ich weiß nicht, ob Sie viel besser werden können, wenn man bedenkt, dass Sie die gesamte Datei durchlesen müssen.
quelle
$_
ist die Standardvariable. Der Zeileneingabeoperator<>
gibt das Ergebnis standardmäßig dort ein, wenn Sie<>
in verwendenwhile
.$_
ist die Themenvariable - sie funktioniert wie das 'es'. In diesem Fall wird ihm<>
jede Zeile zugewiesen. Es wird an mehreren Stellen verwendet, um Code-Unordnung zu reduzieren und beim Schreiben von Einzeilern zu helfen. Das Skript sagt: "Setzen Sie die Summe auf 0, lesen Sie jede Zeile und addieren Sie sie zur Summe. Drucken Sie dann die Summe aus."$sum
. Da dies so einfach ist, können Sie sogar einen Anweisungsmodifikator verwendenwhile
:$sum += $_ while <>; print $sum;
Ich habe dies nicht getestet, aber es sollte funktionieren:
Möglicherweise müssen Sie dem String vor bc "\ n" hinzufügen (wie über Echo), wenn bc EOF und EOL nicht behandelt ...
quelle
bc
gibt einen Syntaxfehler aufgrund des nachgestellten "+" und des Mangels an Zeilenumbruch am Ende aus. Dies funktioniert und verhindert die nutzlose Verwendung voncat
:{ tr "\n" "+" | sed 's/+$/\n/'| bc; } < numbers2.txt
oder<numbers2.txt tr "\n" "+" | sed 's/+$/\n/'| bc
tr "\n" "+" <file | sed 's/+$/\n/' | bc
Hier ist ein anderes:
quelle
Sie können dies mit Alacon tun - dem Befehlszeilenprogramm für die Alasql- Datenbank.
Es funktioniert mit Node.js, daher müssen Sie Node.js und dann das Alasql- Paket installieren :
Um die Summe aus der TXT-Datei zu berechnen, können Sie den folgenden Befehl verwenden:
quelle
Es ist nicht einfacher, alle neuen Zeilen durch zu ersetzen
+
, eine hinzuzufügen0
und an denRuby
Dolmetscher zu senden ?Wenn Sie nicht haben
irb
, können Sie es an sendenbc
, aber Sie müssen alle Zeilenumbrüche außer dem letzten (vonecho
) entfernen . Es ist besser,tr
dies zu verwenden, es sei denn, Sie haben einen Doktortitel insed
.quelle
In Go:
quelle
Bash-Variante
quelle
In der Shell mit awk habe ich das folgende Skript verwendet, um dies zu tun:
quelle