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?
command-line
text-processing
Monty Harder
quelle
quelle
Antworten:
Mit
awk
:$0
ist die aktuelle Zeile. Also füge ich es für jede Zeile hinzutotal
, setze die Zeile auf die neuetotal
und dann ist das Trailing1
eine awk-Verknüpfung - es druckt die aktuelle Zeile für jede wahre Bedingung und wird1
als Bedingung als wahr ausgewertet.quelle
print
auch verwendet werden?print total}
statt$0 = total}1
{print(total += $0)}
In einem Python-Skript:
Benutzen
add_last.py
Führen Sie es mit der Quelldatei und der Zielausgabedatei als Argumente aus:
Erläuterung
Der Code ist ziemlich lesbar, aber im Detail:
Öffnen Sie die Ausgabedatei, um Ergebnisse zu schreiben
Öffnen Sie die Eingabedatei zum Lesen pro Zeile
Lesen Sie die Zeilen und addieren Sie den Wert der neuen Zeile zur Gesamtsumme:
Schreiben Sie das Ergebnis in die Ausgabedatei:
quelle
Nur zum Spaß
Dies funktioniert , indem eine ppending
+p
an jede Zeile der Eingabe, und dann vorbei das Ergebnis an dendc
Rechner , wodann
Das
-e0
Argument wird0
auf dendc
Stapel verschoben, um die Summe zu initialisieren.quelle
real 0m4.234s
In Bash:
quelle
real 0m53.116s
fast eine Minute, auf 1,3 Millionen Zeilen :)So drucken Sie Teilsummen von Ganzzahlen, die auf der Standardeingabe angegeben sind, eine pro Zeile:
Ausführbares Beispiel .
Wenn der Befehl aus irgendeinem Grund zu langsam ist; Sie könnten das C-Programm verwenden:
Geben Sie Folgendes ein, um es zu erstellen und auszuführen:
Ausführbares Beispiel .
UINTMAX_MAX
ist18446744073709551615
.Der C-Code ist um ein Vielfaches schneller als der Befehl awk auf meinem Computer für die Eingabedatei, die generiert wird von:
quelle
accumulate()
itertoolSie möchten wahrscheinlich so etwas:
Erläuterung des Befehls:
sort -n <filename> | uniq -c
sortiert die Eingabe und gibt eine Frequenztabelle zurück| awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
verwandelt den Ausgang in ein schöneres FormatBeispiel:
Eingabedatei
list.txt
:Der Befehl:
quelle
Sie können dies in vim tun. Öffnen Sie die Datei und geben Sie die folgenden Tastenanschläge ein:
Beachten Sie, dass
<C-a>
tatsächlich ctrl-a ist, und<cr>
ist Carriage Return , dh die Enter - Taste.So funktioniert das Zunächst möchten wir das Register 'a' löschen, damit es beim ersten Mal keine Nebenwirkungen hat. Das ist einfach
qaq
. Dann machen wir folgendes:Nachdem dieses rekursive Makro ausgeführt wurde, rufen wir einfach
:wq<cr>
zum Speichern und Beenden auf.quelle
Perl Einzeiler:
Bei 2,5 Millionen Zahlenzeilen dauert die Verarbeitung etwa 6,6 Sekunden:
quelle
real 0m0.908s
, ganz nett.Ein einfacher Bash Einzeiler:
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
vonINPUT_FILE
und addieren ihren numerischen Wert zu unserer Variablenx
und drucken diese Summe während jeder Iteration.Bash ist hier allerdings etwas langsam. Sie können davon ausgehen, dass dies für eine Datei mit 2 Millionen Einträgen etwa 20 bis 30 Sekunden dauert, ohne dass die Ausgabe auf die Konsole gedruckt wird (was unabhängig von der verwendeten Methode sogar noch langsamer ist).
quelle
Ähnlich wie bei @ steeldrivers Antwort, jedoch mit dem etwas weniger arkanen
bc
:Das Schöne an
bc
(unddc
) ist, dass es sich um willkürliche Präzisionsrechner handelt, die also niemals überlaufen oder bei ganzen Zahlen an Präzision leiden.Der
sed
Ausdruck transformiert die Eingabe in:Dies wird dann von ausgewertet
bc
. Diea
Variable bc wird automatisch auf 0 initialisiert. Jede Zeile wird inkrementierta
und dann explizit gedruckt.quelle
real 0m5.642s
auf 1,3 Millionen Zeilen. sed ist wirklich langsam dabei.