Ich möchte die Zeichen von A, T, C, G, N und "-" in einer Datei oder bei Bedarf jeden Buchstaben zählen. Gibt es dazu einen schnellen Unix-Befehl?
command-line
unix
shell
characters
Kirstin
quelle
quelle
[System.IO.File]::ReadAllText("C:\yourfile.txt").ToCharArray() | Group-Object $_ | Sort Count -Descending
Get-Content "C:\eula.3082.txt" | % { $_.ToCharArray() } | Group-Object | Sort Count -Descending
Antworten:
Wenn Sie eine echte Geschwindigkeit wollen:
Ist ein unglaublich schneller Pseudo-One-Liner.
Ein einfacher Test zeigt, dass es auf meiner Core i7-CPU 870 bei 2,93 GHz etwas mehr als 600 MB / s gibt:
Im Gegensatz zu Sortierlösungen wird diese im konstanten Speicher (4 KB) ausgeführt, was sehr nützlich ist, wenn Ihre Datei viel größer als Ihr RAM ist.
Und natürlich können wir mit ein wenig Ellbogenfett 0,7 Sekunden abschneiden:
Netze mit etwas mehr als 1,1 GB / s bei:
Zum Vergleich habe ich einige der anderen Lösungen auf dieser Seite getestet, die ein gewisses Geschwindigkeitsversprechen zu haben schienen.
Die
sed
/awk
solution unternahm eine tapfere Anstrengung, starb jedoch nach 30 Sekunden. Bei einem so einfachen regulären Ausdruck erwarte ich, dass dies ein Fehler in sed ist (GNU sed Version 4.2.1):Die Perl-Methode schien ebenfalls vielversprechend, aber ich gab auf, nachdem ich sie 7 Minuten lang ausgeführt hatte
quelle
grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c
Wird den Trick als Einzeiler machen. Eine kleine Erklärung ist jedoch erforderlich.
grep -o foo.text -e A -e T -e C -e G -e N -e -
Durchsucht die Datei nach den Buchstaben a und g sowie das Zeichen-
für jedes Zeichen, nach dem Sie suchen möchten. Es wird auch ein Zeichen pro Zeile gedruckt.sort
sortiert es in der Reihenfolge. Dies bereitet die Bühne für das nächste Werkzeuguniq -c
zählt die doppelten aufeinanderfolgenden Vorkommen einer Zeile. In diesem Fall erhalten wir, da wir eine sortierte Liste von Zeichen haben, eine genaue Zählung der Zeichen, die wir im ersten Schritt ausgegraut habenWenn foo.txt die Zeichenfolge enthält, ist
GATTACA-
dies das, was ich aus diesem Satz von Befehlen erhalten würdequelle
-o
.Probieren Sie dieses aus, inspiriert von der Antwort von @ Journeyman.
Der Schlüssel ist das Wissen über die Option -o für grep . Dadurch wird die Übereinstimmung aufgeteilt, sodass jede Ausgabezeile einer einzelnen Instanz des Musters entspricht und nicht der gesamten Zeile für jede übereinstimmende Zeile. Angesichts dieses Wissens brauchen wir nur ein Muster und eine Methode, um die Linien zu zählen. Mit einem regulären Ausdruck können wir ein disjunktives Muster erstellen, das mit jedem der von Ihnen genannten Zeichen übereinstimmt:
Dies bedeutet "Übereinstimmung mit A oder T oder C oder G oder N oder -". Das Handbuch beschreibt verschiedene Syntaxregeln für reguläre Ausdrücke, die Sie verwenden können .
Jetzt haben wir eine Ausgabe, die ungefähr so aussieht:
Unser letzter Schritt ist das Zusammenführen und Zählen aller ähnlichen Zeilen, was einfach mit einem
sort | uniq -c
wie in der Antwort von @ Journeyman ausgeführt werden kann. Die Sortierung ergibt folgende Ausgabe:Was, wenn es durchgeleitet wird
uniq -c
, dem entspricht, was wir wollen:Nachtrag: Wenn Sie die Anzahl der Zeichen A, C, G, N, T und - in einer Datei addieren möchten, können Sie die grep-Ausgabe durchleiten,
wc -l
anstattsort | uniq -c
. Es gibt viele verschiedene Dinge, die Sie mit nur geringfügigen Änderungen an diesem Ansatz zählen können.quelle
Ein Zeilenumbruch, der alle Buchstaben mit Python zählt:
... eine YAML-freundliche Ausgabe wie diese erzeugen:
Es ist interessant zu sehen, wie oft Python in Bezug auf die Klarheit des Codes sogar Bash schlagen kann.
quelle
Ähnlich wie bei Guru
awk
:quelle
Nachdem Sie UNIX einige Jahre lang verwendet haben, können Sie eine Reihe kleiner Vorgänge sehr gut miteinander verknüpfen, um verschiedene Filter- und Zählaufgaben auszuführen. Jeder hat seinen eigenen Stil - manche mögen
awk
undsed
, manche mögencut
undtr
. So würde ich es machen:So verarbeiten Sie einen bestimmten Dateinamen:
oder als Filter:
Das funktioniert so:
od -a
trennt die Datei in ASCII-Zeichen.cut -b 9-
Entfernt die Präfix-od
Puts.tr " " \\n
Konvertiert die Leerzeichen zwischen Zeichen in Zeilenumbrüche, sodass pro Zeile ein Zeichen vorhanden ist.egrep -v "^$"
entfernt alle zusätzlichen Leerzeilen, die dadurch entstehen.sort
sammelt Instanzen jedes Charakters zusammen.uniq -c
zählt die Anzahl der Wiederholungen jeder Zeile.Ich fütterte es "Hallo, Welt!" gefolgt von einer neuen Zeile und bekam diese:
quelle
Da der
sed
Teil auf der Antwort von @ Gurus basiert , wird hier ein anderer Ansatz verwendetuniq
, der der Lösung von David Schwartz ähnelt.quelle
[[:alpha:]]
anstelle von ".
in"sed
nur Zeichen und keine Zeilenumbrüche.[[:alpha:]]
wird scheitern, wenn Sie auch versuchen,-
sed -e 's/[^ATCGN-]//g' -e 's/\([ATCGN-]\)/\1\n/g' foo | sort | uniq -c
. Ich weiß jedoch nicht, wie ich die Zeilenumbrüche dort beseitigen soll: \Sie können kombinieren
grep
und dieswc
tun:grep
Durchsucht die angegebenen Dateien nach dem angegebenen Text, und die-o
Option weist sie an, nur die tatsächlichen Übereinstimmungen (dh die Zeichen, nach denen Sie gesucht haben) zu drucken, und nicht die Standardeinstellung, bei der jede Zeile gedruckt wird, in der sich der Suchtext befand gefunden auf.wc
Gibt die Byte-, Wort- und Zeilenzahlen für jede Datei oder in diesem Fall die Ausgabe desgrep
Befehls aus. Die-w
Option fordert Sie auf, Wörter zu zählen, wobei jedes Wort ein Vorkommen Ihres Suchzeichens ist. Natürlich würde die-l
Option (die Zeilen zählt) auch funktionieren, dagrep
jedes Vorkommen Ihres Suchzeichens in einer separaten Zeile gedruckt wird.Um dies für eine Anzahl von Zeichen gleichzeitig zu tun, platzieren Sie die Zeichen in einem Array und führen Sie eine Schleife darüber aus:
Beispiel: Für eine Datei, die die Zeichenfolge enthält, lautet
TGC-GTCCNATGCGNNTCACANN-
die Ausgabe:Weitere Informationen finden Sie unter
man grep
undman wc
.Der Nachteil dieses Ansatzes ist, wie der Benutzer Journeyman Geek unten in einem Kommentar festhält, dass
grep
er für jeden Charakter einmal ausgeführt werden muss. Je nachdem, wie groß Ihre Dateien sind, kann dies zu einer spürbaren Leistungsbeeinträchtigung führen. Andererseits ist es auf diese Weise etwas einfacher, schnell zu erkennen, nach welchen Zeichen gesucht wird, und sie hinzuzufügen / zu entfernen, da sie sich in einer vom Rest des Codes getrennten Zeile befinden.quelle
uniq -c
scheint auch eine bessere Möglichkeit zu sein, eine schön formatierte Ausgabe zu erhalten. Ich bin kein * nix Guru, das Obige ist genau das, was ich aus meinem begrenzten Wissen und einigen Manpages zusammengestellt habe :)Verwenden Sie die Sequenzzeilen aus 22hgp10a.txt, um den Zeitunterschied zwischen grep und awk auf meinem System zu ermitteln.
[Bearbeiten]: Nachdem Sie Daves kompilierte Lösung gesehen haben, vergessen Sie auch awk, da seine in ~ 0,1 Sekunden in dieser Datei abgeschlossen ist, um die Groß- und Kleinschreibung zu berücksichtigen.
Die Groß- und Kleinschreibung von Ghostdog ist in ca. 14 Sekunden erledigt.
Das Sed wird in der akzeptierten Antwort auf diese Frage erklärt .
Das Benchmarking entspricht der akzeptierten Antwort auf diese Frage .
Die akzeptierte Antwort von ghostdog74 war auf diese Frage .
quelle
s/cache[letters[x]]/cache[letters[x]]+cache[toupper(letters[x])]
die Groß- und Kleinschreibung aufheben, ohne die Geschwindigkeit zu beeinträchtigen.Ich denke, dass jede anständige Implementierung eine Sortierung vermeidet. Aber weil es auch eine schlechte Idee ist, alles viermal zu lesen, könnte man irgendwie einen Stream erzeugen, der vier Filter durchläuft, einen für jedes Zeichen, der herausgefiltert wird und bei dem die Streamlängen auch irgendwie berechnet werden.
Die kumulierten Summen sind dann in tmp [0-6] .txt
Bei diesem Ansatz gibt es lediglich 13 Pipes, die in weniger als 1 MB Speicher konvertiert werden.
Natürlich ist meine Lieblingslösung:
quelle
tr
.Ich wusste weder über
uniq
noch übergrep -o
, aber da meine Kommentare zu @JourneymanGeek und @ crazy2be solche Unterstützung hatten, sollte ich es vielleicht zu einer eigenen Antwort machen:Wenn Sie wissen, dass Ihre Datei nur "gute" Zeichen enthält (die Sie zählen möchten), können Sie wählen
Wenn nur einige Zeichen gezählt werden müssen und andere nicht (dh Trennzeichen)
Der erste verwendet den Platzhalter für reguläre Ausdrücke
.
, der mit einem einzelnen Zeichen übereinstimmt. Der zweite verwendet eine 'Menge von akzeptierten Zeichen' ohne bestimmte Reihenfolge, mit der Ausnahme, dass-
die letzte sein muss (A-C
wird als 'beliebiges Zeichen zwischenA
und ' interpretiertC
). In diesem Fall sind Anführungszeichen erforderlich, damit Ihre Shell nicht versucht, diese zu erweitern, um etwaige Einzelzeichendateien zu überprüfen (und einen "no match" -Fehler zu erzeugen, wenn keine vorhanden sind).Beachten Sie, dass "sort" auch ein
-u
Nique-Flag hat, sodass Dinge nur einmal gemeldet werden, aber kein Companion-Flag, um Duplikate zu zählen. Diesuniq
ist in der Tat obligatorisch.quelle
-
muss nicht zuletzt kommen, wenn Sie es mit einem Backslash entkommen:'[A\-CTGN]'
sollte gut funktionieren.Ein dummer:
tr
löscht (-d
) alle Zeichen außer (-c
) ATCGN-iconv
nach ucs2 konvertieren (UTF16 auf 2 Byte begrenzt), um nach jedem Byte ein 0-Byte hinzuzufügen,tr
, um diese NUL-Zeichen in NL zu übersetzen. Jetzt ist jedes Zeichen in einer eigenen Zeilesort | uniq -c
um jede einzelne Zeile zu zählenDies ist eine Alternative zur nicht standardmäßigen
-o
grep-Option (GNU) .quelle
Das Ausgabeformat ist nicht das beste ...
Theorie der Arbeitsweise:
Die Geschwindigkeit scheint 60MBps + zu sein
quelle
Beispieldatei:
Befehl:
quelle
Ein paar andere kombinieren
Hinzufügen
| sort -nr
, um die Ergebnisse in der Reihenfolge der Häufigkeit anzuzeigen.quelle
Kurze Antwort:
Wenn es die Umstände zulassen, vergleichen Sie die Dateigrößen niedriger Zeichensätze mit denen ohne Zeichen, um einen Offset zu erhalten und nur die Bytes zu zählen.
Ah, aber die verworrenen Details:
Das sind alles Ascii-Charaktere. Ein Byte pro. Dateien haben natürlich zusätzliche Metadaten für eine Vielzahl von Dingen, die vom Betriebssystem und der App, die es erstellt hat, verwendet werden. In den meisten Fällen würde ich davon ausgehen, dass diese unabhängig von den Metadaten den gleichen Speicherplatz belegen, aber ich würde versuchen, identische Umstände beizubehalten, wenn Sie den Ansatz zuerst testen und dann überprüfen, ob Sie einen konstanten Versatz haben, bevor Sie sich keine Gedanken darüber machen. Das andere Problem ist, dass Zeilenumbrüche normalerweise zwei ASCII-Leerzeichen enthalten und Tabulatoren oder Leerzeichen jeweils eins sind. Wenn Sie sicher sein können, dass diese vorhanden sein werden und es keine Möglichkeit gibt, vorher zu wissen, wie viele es sind, würde ich jetzt aufhören zu lesen.
Es mag wie eine Menge Einschränkungen erscheinen, aber wenn Sie sie leicht feststellen können, erscheint mir dies als der Ansatz mit der einfachsten / besten Leistung, wenn Sie eine Menge davon betrachten müssen (was wahrscheinlich ist, wenn es sich um DNA handelt). Eine Tonne von Dateien auf Länge zu prüfen und eine Konstante zu subtrahieren, wäre schneller, als bei jedem grep (oder ähnlichem) auszuführen.
Wenn:
Und zwei Dinge, die vielleicht nicht wichtig sind, mit denen ich aber zuerst testen würde
Versuchen Sie, den Versatz wie folgt zu ermitteln:
Vergleichen Sie eine leere Datei mit einer mit ein paar leicht zu zählenden Zeichen mit einer mit ein paar weiteren Zeichen. Wenn Sie die leere Datei von den beiden anderen Dateien subtrahieren, erhalten Sie Bytezahlen, die der Anzahl der Zeichen entsprechen, sind Sie fertig. Überprüfen Sie die Dateilängen und subtrahieren Sie diese leere Menge. Wenn Sie versuchen möchten, mehrzeilige Dateien zu ermitteln, fügen die meisten Editoren zwei Ein-Byte-Sonderzeichen für Zeilenumbrüche hinzu, da eines von Microsoft eher ignoriert wird. In diesem Fall müssen Sie jedoch mindestens nach Leerzeichen suchen du könntest es genauso gut alles mit grep machen.
quelle
Haskell Weg:
es funktioniert so:
Kompilieren und Verwenden von:
Nicht gut für große Dateien.
quelle
Schneller Perl-Hack:
-n
: Iteriere über Eingabezeilen, aber drucke nichts für sie-l
: Zeilenumbrüche automatisch entfernen oder hinzufügenwhile
: Alle Vorkommen Ihrer angeforderten Symbole in der aktuellen Zeile durchlaufenEND
: Am Ende werden die Ergebnisse gedruckt%a
: Hash, wo die Werte gespeichert sindZeichen, die überhaupt nicht vorkommen, werden nicht in das Ergebnis einbezogen.
quelle