Qual è il modo più veloce per contare il numero di ogni personaggio in un file?


121

Voglio contare i caratteri G's N e "-" di A's T's C in un file, o ogni lettera, se necessario, c'è un rapido comando Unix per farlo?


56
Conteggio delle basi nei filamenti di DNA?
Indrek,

12
Adoro questa domanda, così tanti approcci e strumenti diversi utilizzati per risolvere lo stesso problema.
Journeyman Geek

10
Heh, questo è un codice-golf borderline
Earlz,

13
se qualcuno è interessato alla versione Windows PowerShell:[System.IO.File]::ReadAllText("C:\yourfile.txt").ToCharArray() | Group-Object $_ | Sort Count -Descending
Guillaume86,

4
Ok, penso di aver trovato il modo puro di PS:Get-Content "C:\eula.3082.txt" | % { $_.ToCharArray() } | Group-Object | Sort Count -Descending
Guillaume86,

Risposte:


136

Se vuoi un po 'di velocità reale:

echo 'int cache[256],x,y;char buf[4096],letters[]="tacgn-"; int main(){while((x=read(0,buf,sizeof buf))>0)for(y=0;y<x;y++)cache[(unsigned char)buf[y]]++;for(x=0;x<sizeof letters-1;x++)printf("%c: %d\n",letters[x],cache[letters[x]]);}' | gcc -w -xc -; ./a.out < file; rm a.out;

È uno pseudo-one-liner incredibilmente veloce.

Un semplice test mostra che sulla mia CPU Core i7 870 a 2,93 GHz conta poco più di 600 MB / s:

$ du -h bigdna 
1.1G    bigdna

time ./a.out < bigdna 
t: 178977308
a: 178958411
c: 178958823
g: 178947772
n: 178959673
-: 178939837

real    0m1.718s
user    0m1.539s
sys     0m0.171s

A differenza delle soluzioni che prevedono l'ordinamento, questo viene eseguito in memoria costante (4K), che è molto utile, se il tuo file è molto più grande del tuo ram.

E, naturalmente, con un po 'di grasso al gomito, possiamo radere 0,7 secondi:

echo 'int cache[256],x,buf[4096],*bp,*ep;char letters[]="tacgn-"; int main(){while((ep=buf+(read(0,buf,sizeof buf)/sizeof(int)))>buf)for(bp=buf;bp<ep;bp++){cache[(*bp)&0xff]++;cache[(*bp>>8)&0xff]++;cache[(*bp>>16)&0xff]++;cache[(*bp>>24)&0xff]++;}for(x=0;x<sizeof letters-1;x++)printf("%c: %d\n",letters[x],cache[letters[x]]);}' | gcc -O2 -xc -; ./a.out < file; rm a.out;

Reti poco più di 1,1 GB / s finendo in:

real    0m0.943s
user    0m0.798s
sys     0m0.134s

Per fare un confronto, ho testato alcune delle altre soluzioni in questa pagina che sembravano avere una sorta di velocità promessa.

La soluzione sed/ awkfece uno sforzo coraggioso, ma morì dopo 30 secondi. Con una regex così semplice, mi aspetto che questo sia un bug in sed (GNU sed versione 4.2.1):

$ time sed 's/./&\n/g' bigdna | awk '!/^$/{a[$0]++}END{for (i in a)print i,a[i];}' 
sed: couldn't re-allocate memory

real    0m31.326s
user    0m21.696s
sys     0m2.111s

Anche il metodo perl sembrava promettente, ma ho rinunciato dopo averlo eseguito per 7 minuti

time perl -e 'while (<>) {$c{$&}++ while /./g} print "$c{$_} $_\n" for keys %c' < bigdna 
^C

real    7m44.161s
user    4m53.941s
sys     2m35.593s

1
+1 Per una soluzione sana quando contiene molti dati e non solo una manciata di byte. I file si trovano nella cache del disco, no?
Daniel Beck

2
La cosa bella è che ha una complessità di O (N) in elaborazione e O (1) in memoria. I tubi di solito hanno O (N log N) in elaborazione (o anche O (N ^ 2)) e O (N) in memoria.
Martin Ueding,

73
Tuttavia, stai allungando un po 'la definizione di "riga di comando".
Gerrit,

11
Piega epica dei requisiti della domanda -Io approvo; p. superuser.com/a/486037/10165 <- qualcuno ha eseguito benchmark e questa è l'opzione più veloce.
Journeyman Geek

2
+1 Mi apprezzo un buon uso di C nei posti giusti.
Jeff Ferland,

119

grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c

Farà il trucco come una fodera. È necessaria una piccola spiegazione.

grep -o foo.text -e A -e T -e C -e G -e N -e -greps il file foo.text per le lettere a e ge il carattere -per ogni personaggio che si desidera cercare. Lo stampa anche un carattere una riga.

sortordina in ordine. Questo pone le basi per lo strumento successivo

uniq -cconta le occorrenze consecutive duplicate di qualsiasi riga. In questo caso, dal momento che abbiamo un elenco ordinato di personaggi, otteniamo un conteggio accurato di quando i personaggi che abbiamo greppato nel primo passaggio

Se foo.txt contenesse la stringa GATTACA-questo è ciò che otterrei da questo set di comandi

[geek@atremis ~]$ grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c
      1 -
      3 A
      1 C
      1 G
      2 T

8
Magia sanguinante unix! : D
Pitto,

27
se ci sono solo caratteri CTAG nei tuoi file, la regexp stessa diventa inutile, giusto? grep -o. | ordina | uniq -c funzionerebbe ugualmente bene, afaik.
sylvainulg,

7
+1 Uso grep da 25 anni e non lo sapevo -o.
LarsH,

9
@JourneymanGeek: il problema è che genera molti dati che vengono quindi inoltrati per ordinare. Sarebbe più economico lasciare che un programma analizzi ciascun personaggio. Vedi la risposta di Dave per una risposta di complessità della memoria O (1) anziché O (N).
Martin Ueding,

2
@Pitto Le build native di coreutils di Windows sono ampiamente disponibili - chiedi a Google o a qualcuno
OrangeDog

46

Prova questo, ispirato alla risposta di @ Journeyman.

grep -o -E 'A|T|C|G|N|-' foo.txt | sort | uniq -c

La chiave sta conoscendo l'opzione -o per grep . Questo divide la corrispondenza, in modo che ogni linea di output corrisponda a una singola istanza del modello, piuttosto che all'intera riga per qualsiasi riga corrispondente. Data questa conoscenza, tutto ciò di cui abbiamo bisogno è un modello da usare e un modo per contare le linee. Usando una regex, possiamo creare un modello disgiuntivo che corrisponderà a qualsiasi dei personaggi che menzioni:

A|T|C|G|N|-

Questo significa "abbina A o T o C o G o N o -". Il manuale descrive varie sintassi di espressioni regolari che è possibile utilizzare .

Ora abbiamo un output simile a questo:

$ grep -o -E 'A|T|C|G|N|-' foo.txt 
A
T
C
G
N
-
-
A
A
N
N
N

Il nostro ultimo passo è quello di unire e contare tutte le linee simili, che possono essere semplicemente realizzate con un sort | uniq -c, come nella risposta di @ Journeyman. L'ordinamento ci dà output in questo modo:

$ grep -o -E 'A|T|C|G|N|-' foo.txt | sort
-
-
A
A
A
C
G
N
N
N
N
T

Che, una volta convogliato uniq -c, assomiglia finalmente a ciò che vogliamo:

$ grep -o -E 'A|T|C|G|N|-' foo.txt | sort | uniq -c
      2 -
      3 A
      1 C
      1 G
      4 N
      1 T

Addendum: se si desidera sommare il numero di caratteri A, C, G, N, T e - in un file, è possibile reindirizzare l'output grep wc -lanziché sort | uniq -c. Ci sono molte cose diverse che puoi contare solo con lievi modifiche a questo approccio.


Ho davvero bisogno di approfondire i rabbitholes che sono coreutils e regex. Questo è un po 'più elegante del mio per questo; p
Journeyman Geek

2
@JourneymanGeek: ascoltare il regex vale la pena, poiché è utile per così tante cose. Basta capire i suoi limiti e non abusare del potere tentando di fare cose al di fuori dell'ambito delle capacità delle regex, come cercare di analizzare XHTML .
crazy2be

20
grep -o '[ATCGN-]' potrebbe essere un po 'più leggibile qui.
sylvainulg,

14

Una riga che conta tutte le lettere usando Python:

$ python -c "import collections, pprint; pprint.pprint(dict(collections.Counter(open('FILENAME_HERE', 'r').read())))"

... producendo un output compatibile con YAML come questo:

{'\n': 202,
 ' ': 2153,
 '!': 4,
 '"': 62,
 '#': 12,
 '%': 9,
 "'": 10,
 '(': 84,
 ')': 84,
 '*': 1,
 ',': 39,
 '-': 5,
 '.': 121,
 '/': 12,
 '0': 5,
 '1': 7,
 '2': 1,
 '3': 1,
 ':': 65,
 ';': 3,
 '<': 1,
 '=': 41,
 '>': 12,
 '@': 6,
 'A': 3,
 'B': 2,
 'C': 1,
 'D': 3,
 'E': 25}

È interessante vedere come la maggior parte delle volte Python possa battere facilmente anche bash in termini di chiarezza del codice.


11

Simile al awkmetodo di Guru :

perl -e 'while (<>) {$c{$&}++ while /./g} print "$c{$_} $_\n" for keys %c'

10

Dopo aver utilizzato UNIX per un paio d'anni, sei molto abile nel collegare insieme una serie di piccole operazioni per eseguire varie attività di filtro e conteggio. Ognuno ha il proprio stile - alcuni come awke sed, alcuni come cute tr. Ecco come lo farei:

Per elaborare un determinato nome file:

 od -a FILENAME_HERE | cut -b 9- | tr " " \\n | egrep -v "^$" | sort | uniq -c

o come filtro:

 od -a | cut -b 9- | tr " " \\n | egrep -v "^$" | sort | uniq -c

Funziona così:

  1. od -a separa il file in caratteri ASCII.
  2. cut -b 9-elimina i prefissi od.
  3. tr " " \\n converte gli spazi tra i personaggi in newline in modo che ci sia un carattere per riga.
  4. egrep -v "^$" elimina tutte le righe vuote in più che questo crea.
  5. sort raccoglie le istanze di ogni personaggio insieme.
  6. uniq -c conta il numero di ripetizioni di ciascuna riga.

L'ho nutrito "Ciao, mondo!" seguito da una nuova riga e ottenuto questo:

  1 ,
  1 !
  1 d
  1 e
  1 H
  3 l
  1 nl
  2 o
  1 r
  1 sp
  1 w

9

La sedparte si basa sulla risposta di @ Guru , ecco un altro approccio che utilizza uniq, simile alla soluzione di David Schwartz.

$ cat foo
aix
linux
bsd
foo
$ sed 's/\(.\)/\1\n/g' foo | sort | uniq -c
4 
1 a
1 b
1 d
1 f
2 i
1 l
1 n
2 o
1 s
1 u
2 x

1
Utilizzare [[:alpha:]]anziché .in sedper abbinare solo i caratteri e non le nuove righe.
Claudio,

1
[[:alpha:]]fallirà se stai anche cercando di abbinare cose del genere -, che è stato menzionato nella domanda
Izkata,

Corretta. Potrebbe essere più bello di aggiungere una seconda espressione di sed per filtrare prima tutto il resto e poi abbinare in modo esplicito sui caratteri desiderati: sed -e 's/[^ATCGN-]//g' -e 's/\([ATCGN-]\)/\1\n/g' foo | sort | uniq -c. Tuttavia, non so come sbarazzarmi delle newline lì: \
Claudio

7

Puoi combinare grepe wcfare questo:

grep -o 'character' file.txt | wc -w

grepcerca il file specificato per il testo specificato e l' -oopzione dice di stampare solo le corrispondenze effettive (cioè i caratteri che stavi cercando), piuttosto che il valore predefinito che è stampare ogni riga in cui il testo di ricerca era trovato su.

wcstampa il conteggio di byte, parole e righe per ogni file o, in questo caso, l'output del grepcomando. L' -wopzione indica di contare le parole, ciascuna delle quali è una ricorrenza del tuo carattere di ricerca. Naturalmente, anche l' -lopzione (che conta le righe) funzionerebbe, poiché grepstampa ogni occorrenza del tuo carattere di ricerca su una riga separata.

Per fare ciò per un numero di caratteri contemporaneamente, inseriscili in un array e passaci sopra:

chars=(A T C G N -)
for c in "${chars[@]}"; do echo -n $c ' ' && grep -o $c file.txt | wc -w; done

Esempio: per un file contenente la stringa TGC-GTCCNATGCGNNTCACANN-, l'output sarebbe:

A  3
T  4
C  6
G  4
N  5
-  2

Per ulteriori informazioni, vedere man grepe man wc.


Il rovescio della medaglia di questo approccio, come osserva l'utente Journeyman Geek di seguito in un commento, è che grepdeve essere eseguito una volta per ogni personaggio. A seconda della dimensione dei file, ciò può comportare un notevole calo delle prestazioni. D'altra parte, quando fatto in questo modo è un po 'più facile vedere rapidamente quali caratteri vengono cercati e aggiungerli / rimuoverli, poiché si trovano su una riga separata dal resto del codice.


3
avrebbero bisogno di ripeterlo per carattere che vogliono ... Aggiungerei. Potrei giurare che c'è una soluzione più elegante ma ha bisogno di più frugamenti; p
Journeyman Geek

@JourneymanGeek Ottimo punto. Un approccio che mi viene in mente è quello di mettere i personaggi in un array e passarci attraverso. Ho aggiornato il mio post.
Indrek,

IMO troppo complesso. Usa grep -ea -et e così via. Se lo metti in un array e lo attraversi, non dovresti eseguire il ciclo grep una volta per personaggio?
Journeyman Geek

@JourneymanGeek Probabilmente hai ragione. uniq -csembra anche un modo migliore per ottenere un output ben formattato. Non sono un * nix guru, quanto sopra è proprio quello che sono riuscito a mettere insieme dalle mie conoscenze limitate e da alcune pagine man :)
Indrek,

Anche io; p, e uno dei miei incarichi dell'ultimo mandato ha comportato l'ordinamento di circa 5000 voci della rubrica e uniq ha reso MOLTO più semplice.
Journeyman Geek

7

Usando le linee di sequenza da 22hgp10a.txt la differenza di temporizzazione tra grep e awk sul mio sistema rende l'utilizzo di awk la strada da percorrere ...

[Modifica]: dopo aver visto la soluzione compilata di Dave dimenticare anche awk, poiché è stato completato in circa 0,1 secondi su questo file per il conteggio con distinzione tra maiuscole e minuscole.

# A nice large sample file.
wget http://gutenberg.readingroo.ms/etext02/22hgp10a.txt

# Omit the regular text up to the start `>chr22` indicator.
sed -ie '1,/^>chr22/d' 22hgp10a.txt

sudo test # Just get sudo setup to not ask for password...

# ghostdog74 answered a question <linked below> about character frequency which
# gave me all case sensitive [ACGNTacgnt] counts in ~10 seconds.
sudo chrt -f 99 /usr/bin/time -f "%E elapsed, %c context switches" \
awk -vFS="" '{for(i=1;i<=NF;i++)w[$i]++}END{for(i in w) print i,w[i]}' 22hgp10a.txt

# The grep version given by Journeyman Geek took a whopping 3:41.47 minutes
# and yielded the case sensitive [ACGNT] counts.
sudo chrt -f 99 /usr/bin/time -f "%E elapsed, %c context switches" \
grep -o foo.text -e A -e T -e C -e G -e N -e -|sort|uniq -c

La versione senza distinzione tra maiuscole e minuscole di ghostdog è stata completata in ~ 14 secondi.

La sed è spiegata nella risposta accettata a questa domanda .
Il benchmarking è come nella risposta accettata a questa domanda .
La risposta accettata da ghostdog74 è stata a questa domanda .


1
Puoi s/cache[letters[x]]/cache[letters[x]]+cache[toupper(letters[x])]estrarlo per renderlo insensibile alle maiuscole senza comprometterne la velocità.
Dave,

6

Penso che qualsiasi implementazione decente eviti l'ordinamento. Ma poiché è anche una cattiva idea leggere tutto 4 volte, penso che si potrebbe in qualche modo generare un flusso che attraversa 4 filtri, uno per ogni carattere, che viene filtrato e in cui in qualche modo vengono anche calcolate le lunghezze del flusso.

time cat /dev/random | tr -d -C 'AGCTN\-' | head -c16M >dna.txt
real    0m5.797s
user    0m6.816s
sys     0m1.371s

$ time tr -d -C 'AGCTN\-' <dna.txt | tee >(wc -c >tmp0.txt) | tr -d 'A' | 
tee >(wc -c >tmp1.txt) | tr -d 'G' | tee >(wc -c >tmp2.txt) | tr -d 'C' | 
tee >(wc -c >tmp3.txt) | tr -d 'T' | tee >(wc -c >tmp4.txt) | tr -d 'N' | 
tee >(wc -c >tmp5.txt) | tr -d '\-' | wc -c >tmp6.txt && cat tmp[0-6].txt

real    0m0.742s
user    0m0.883s
sys     0m0.866s

16777216
13983005
11184107
8387205
5591177
2795114
0

Le somme cumulative sono quindi in tmp [0-6] .txt .. quindi il lavoro è ancora in corso

Ci sono solo 13 pipe in questo approccio, che converte in meno di 1 Mb di memoria.
Naturalmente la mia soluzione preferita è:

time cat >f.c && gcc -O6 f.c && ./a.out
# then type your favourite c-program
real    0m42.130s

Questo è un ottimo uso di tr.
Adavid,

4

Non sapevo uniqné riguardo grep -o, ma dato che i miei commenti su @JourneymanGeek e @ crazy2be hanno avuto un tale supporto, forse dovrei trasformarlo in una risposta a sé stante:

Se sai che ci sono solo caratteri "buoni" (quelli che vuoi contare) nel tuo file, puoi scegliere

grep . -o YourFile | sort | uniq -c

Se solo alcuni caratteri devono essere contati e altri no (es. Separatori)

grep '[ACTGN-]' YourFile | sort | uniq -c

Il primo utilizza il carattere jolly di espressione regolare ., che corrisponde a qualsiasi singolo carattere. Il secondo usa un 'insieme di caratteri accettati', senza un ordine specifico, tranne che -deve arrivare per ultimo ( A-Cviene interpretato come 'qualsiasi carattere tra Ae C). In questo caso sono necessarie delle virgolette in modo che la shell non tenti di espanderla per verificare l'eventuale presenza di file a carattere singolo (e produrre un errore "nessuna corrispondenza" se nessuna).

Si noti che "sort" ha anche un -uflag di nicchia in modo che riporti le cose solo una volta, ma nessun flag di accompagnamento per contare i duplicati, quindi uniqè davvero obbligatorio.


-non deve arrivare per ultimo se si evita con una barra rovesciata: '[A\-CTGN]'dovrebbe funzionare bene.
Indrek,

2

Uno sciocco:

tr -cd ATCGN- | iconv -f ascii -t ucs2 | tr '\0' '\n' | sort | uniq -c
  • trper eliminare ( -d) tutti i caratteri ma ( -c) ATCGN-
  • iconv per convertire in ucs2 (UTF16 limitato a 2 byte) per aggiungere uno 0 byte dopo ogni byte,
  • un altro trper tradurre quei caratteri NUL in NL. Ora ogni personaggio è sulla sua linea
  • sort | uniq -cper contare ogni riga uniq

Questa è un'alternativa -oall'opzione grep non standard (GNU) .


Potresti dare una breve spiegazione dei comandi e della logica qui?
Andrew Lambert,

2
time $( { tr -cd ACGTD- < dna.txt | dd | tr -d A | dd | tr -d C | dd | tr -d G |
dd | tr -d T | dd | tr -d D | dd | tr -d - | dd >/dev/null; } 2>tmp ) &&
grep byte < tmp | sort -r -g | awk '{ if ((s-$0)>=0) { print s-$0} s=$0 }'

Il formato di output non è il migliore ...

real    0m0.176s
user    0m0.200s
sys     0m0.160s
2069046
2070218
2061086
2057418
2070062
2052266

Teoria dell'operazione:

  • $ ({command | command} 2> tmp) reindirizza lo standard del flusso su un file temporaneo.
  • dd invia stdin a stdout e genera il numero di byte passati a stderr
  • tr -d filtra un carattere alla volta
  • grep e sort filtra l'output di dd in ordine decrescente
  • awk calcola la differenza
  • l'ordinamento viene utilizzato solo nella fase di post-elaborazione per gestire l'incertezza dell'ordine di uscita delle istanze di dd

La velocità sembra essere di 60 Mbps +


Miglioramenti: sbarazzarsi di tmp? usa 'incolla' per stampare la lettera in questione?
Aki Suihkonen,

1

File di esempio:

$ cat file
aix
unix
linux

Comando:

$ sed 's/./&\n/g' file | awk '!/^$/{a[$0]++}END{for (i in a)print i,a[i];}'
u 2
i 3
x 3
l 1
n 2
a 1

-1 per mancanza di chiarezza e per la pubblicazione di una riga senza spiegazione. AFAIK, questa potrebbe essere una bomba a forcella
PPC,

1

Combinando alcuni altri

chars='abcdefghijklmnopqrstuvwxyz-'
grep -o -i "[$chars]" foo|sort | uniq -c

Aggiungi | sort -nrper vedere i risultati in ordine di frequenza.


1

Risposta breve:

Se le circostanze lo consentono, confrontare le dimensioni dei file di set di caratteri bassi con uno senza caratteri per ottenere un offset e contare solo i byte.

Ah, ma i dettagli aggrovigliati:

Questi sono tutti personaggi di Ascii. Un byte per. I file ovviamente hanno metadati extra anteposti a una varietà di elementi utilizzati dal sistema operativo e dall'app che lo ha creato. Nella maggior parte dei casi, mi aspetto che questi occupino la stessa quantità di spazio indipendentemente dai metadati, ma proverei a mantenere circostanze identiche quando provi per la prima volta l'approccio e quindi verifichi che hai un offset costante prima di non preoccuparti. L'altro aspetto è che le interruzioni di riga in genere coinvolgono due caratteri ASCII spazi bianchi e tutte le schede o gli spazi sarebbero uno ciascuno. Se puoi essere certo che questi saranno presenti e non c'è modo di sapere quanti in anticipo, smetterei di leggere ora.

Potrebbe sembrare un sacco di vincoli, ma se riesci a stabilirli facilmente, questo mi sembra l'approccio più semplice / con le migliori prestazioni se hai un sacco di questi da guardare (il che sembra probabile che sia il DNA). Controllare una tonnellata di file per la lunghezza e sottrarre una costante sarebbe più veloce che eseguire grep (o simili) su ognuno.

Se:

  • Queste sono semplici stringhe non interrotte in file di testo puri
  • Sono in identici tipi di file creati dallo stesso editor di testo vaniglia non formattante come Scite (incollare va bene finché controlli spazi / ritorni) o qualche programma base che qualcuno ha scritto

E due cose che potrebbero non importare, ma vorrei provare prima

  • I nomi dei file hanno la stessa lunghezza
  • I file si trovano nella stessa directory

Prova a trovare l'offset procedendo come segue:

Confronta un file vuoto con uno con pochi caratteri facilmente contabili dall'uomo con uno con pochi caratteri in più. Se sottraendo il file vuoto da entrambi gli altri due file si ottengono conteggi di byte corrispondenti al conteggio dei caratteri, il gioco è fatto. Controlla la lunghezza del file e sottrai quell'importo vuoto. Se vuoi provare a capire i file multi-linea, la maggior parte degli editor allegano due caratteri speciali a un byte per le interruzioni di riga poiché uno tende a essere ignorato da Microsoft ma dovresti almeno grep per i caratteri di spazio bianco nel qual caso potresti anche fare tutto con grep.


1

Modo Haskell :

import Data.Ord
import Data.List
import Control.Arrow

main :: IO ()
main = interact $
  show . sortBy (comparing fst) . map (length &&& head) . group . sort

funziona così:

112123123412345
=> sort
111112222333445
=> group
11111 2222 333 44 5
=> map (length &&& head)
(5 '1') (4 '2') (3 '3') (2 '4') (1,'5')
=> sortBy (comparing fst)
(1 '5') (2 '4') (3 '3') (4 '2') (5 '1')
=> one can add some pretty-printing here
...

compilare e utilizzare:

$ ghc -O2 q.hs
[1 of 1] Compiling Main             ( q.hs, q.o )
Linking q ...
$ echo 112123123412345 | ./q
[(1,'\n'),(1,'5'),(2,'4'),(3,'3'),(4,'2'),(5,'1')]%       
$ cat path/to/file | ./q
...

forse non va bene per file enormi.


1

Perl veloce:

perl -nle 'while(/[ATCGN]/g){$a{$&}+=1};END{for(keys(%a)){print "$_:$a{$_}"}}'
  • -n: Iterate sulle righe di input ma non stampa nulla per loro
  • -l: Elimina o aggiunge automaticamente le interruzioni di riga
  • while: scorre su tutte le occorrenze dei simboli richiesti nella riga corrente
  • END: Alla fine, stampa i risultati
  • %a: Hash in cui sono memorizzati i valori

I personaggi che non si presentano affatto non saranno inclusi nel risultato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.