Quel est le moyen le plus rapide de compter le nombre de caractères dans un fichier?


121

Je souhaite compter les caractères "-" dans un fichier, ou chaque lettre si nécessaire, existe-t-il une commande Unix rapide pour le faire?


56
Compter les bases dans les brins d'ADN?
Indrek

12
J'aime cette question, tant d'approches et d'outils différents utilisés pour résoudre le même problème.
Journeyman Geek

10
Heh, c'est limite code-golf
Earlz

13
si quelqu'un est intéressé par la version Windows PowerShell:[System.IO.File]::ReadAllText("C:\yourfile.txt").ToCharArray() | Group-Object $_ | Sort Count -Descending
Guillaume86

4
Ok, je pense avoir trouvé la voie pure du PS:Get-Content "C:\eula.3082.txt" | % { $_.ToCharArray() } | Group-Object | Sort Count -Descending
Guillaume86

Réponses:


136

Si vous voulez de la vitesse réelle:

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;

Est un pseudo-one-liner incroyablement rapide.

Un simple test montre que sur mon CPU Core i7 870 à 2,93 GHz, elle compte à peine plus de 600 Mo / 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

Contrairement aux solutions impliquant le tri, celle-ci fonctionne en mémoire constante (4K), ce qui est très utile si votre fichier est beaucoup plus volumineux que votre RAM.

Et, bien sûr, avec un peu de graisse pour coude, nous pouvons gagner 0,7 seconde:

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;

Filets juste au-dessus de 1,1 Go / s en finition en:

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

À titre de comparaison, j’ai testé certaines des autres solutions de cette page qui semblaient prometteuses.

La sed/ awksolution a fait un vaillant effort, mais il est mort au bout de 30 secondes. Avec une expression aussi simple, je m'attends à ce que ce soit un bogue dans sed (version 4.2.1 de GNU sed):

$ 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

La méthode perl semblait également prometteuse, mais j’ai abandonné après 7 minutes d’exécution.

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 Pour une solution rationnelle quand il y a beaucoup de données, et pas seulement une poignée d'octets. Les fichiers sont dans le cache du disque, n'est-ce pas?
Daniel Beck

2
La chose intéressante est qu'il a une complexité de O (N) dans le traitement et O (1) en mémoire. Les tuyaux ont généralement O (N log N) en traitement (ou même O (N ^ 2)) et O (N) en mémoire.
Martin Ueding

73
Vous élargissez cependant un peu la définition de "ligne de commande".
gerrit

11
Flexion épique des exigences de la question - J'approuve, p. superuser.com/a/486037/10165 <- quelqu'un a exécuté des tests de performance , ce qui est l'option la plus rapide.
Journeyman Geek

2
+1 J'apprécie le bon usage de C aux bons endroits.
Jeff Ferland

119

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

Fera le tour comme un one-line. Une petite explication est nécessaire cependant.

grep -o foo.text -e A -e T -e C -e G -e N -e -greps le fichier foo.text pour les lettres a et g et le caractère -pour chaque caractère que vous souhaitez rechercher. Il imprime également un caractère par ligne.

sortle trie dans l'ordre. Cela ouvre la voie à l'outil suivant

uniq -ccompte les occurrences consécutives en double d'une ligne. Dans ce cas, puisque nous avons une liste triée de caractères, nous obtenons un décompte précis du moment où les caractères que nous avons extirpés à la première étape

Si foo.txt contenait la chaîne, voici GATTACA-ce que j'obtiendrais de cet ensemble de commandes

[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
Bloody Unix magique! : D
Pitto

27
s'il n'y a que des caractères CTAG dans vos fichiers, l'expression rationnelle elle-même devient inutile, n'est-ce pas? grep -o. | trier | Uniq -c fonctionnerait tout aussi bien, autant que je sache.
Sylvainulg 10/10/2012

7
+1 J'utilise grep depuis 25 ans et je ne le savais pas -o.
LarsH

9
@JourneymanGeek: Le problème, c'est qu'il génère beaucoup de données qui sont ensuite transmises pour être triées. Il serait moins coûteux de laisser un programme analyser chaque caractère. Voir la réponse de Dave pour une réponse de complexité de mémoire O (1) à la place de O (N).
Martin Ueding

2
@Pitto Les versions natives Windows de coreutils sont largement disponibles - il suffit de demander à Google ou à un autre utilisateur
OrangeDog

46

Essayez celui-ci, inspiré par la réponse de @ Journeyman.

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

La clé est de connaître l'option -o pour grep . Cela divise la correspondance, de sorte que chaque ligne de sortie correspond à une seule instance du modèle, plutôt qu'à la ligne entière de toute ligne correspondante. Compte tenu de ces connaissances, tout ce dont nous avons besoin est un modèle à utiliser et un moyen de compter les lignes. En utilisant une regex, nous pouvons créer un motif disjonctif qui correspondra à n’importe quel des caractères que vous mentionnez:

A|T|C|G|N|-

Cela signifie "faire correspondre A ou T ou C ou G ou N ou -". Le manuel décrit diverses syntaxes d’expression régulière que vous pouvez utiliser .

Nous avons maintenant une sortie qui ressemble à ceci:

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

Notre dernière étape consiste à fusionner et à compter toutes les lignes similaires, ce qui peut simplement être accompli avec un sort | uniq -c, comme dans la réponse de @ Journeyman. La sorte nous donne la sortie comme ceci:

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

Ce qui, uniq -cfinalement, ressemble à ce que nous voulons:

$ 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: Si vous souhaitez totaliser le nombre de caractères A, C, G, N, T et - dans un fichier, vous pouvez diriger la sortie de grep au wc -llieu de sort | uniq -c. Il y a beaucoup de choses différentes que vous pouvez compter avec seulement de légères modifications à cette approche.


J'ai vraiment besoin de fouiller dans les rabbitholes qui sont coreutils et regex. C’est un peu plus élégant que le mien; p
Compagnon Geek

2
@JourneymanGeek: Apprendre regex vaut bien la peine, car il est utile pour tant de choses. Comprenez simplement que c'est des limites, et n'abusez pas du pouvoir en essayant de faire des choses en dehors de la portée des capacités régulières, comme essayer d'analyser XHTML .
Crazy2be

20
grep -o '[ATCGN-]' pourrait être un peu plus lisible ici.
Sylvainulg

14

Une doublure comptant toutes les lettres utilisant Python:

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

... produisant une sortie conviviale YAML comme ceci:

{'\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}

Il est intéressant de voir comment la plupart du temps, Python peut facilement battre même en termes de clarté du code.


11

Similaire à la awkméthode de Guru :

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

10

Après avoir utilisé UNIX pendant quelques années, vous maîtrisez parfaitement les opérations de liaison entre plusieurs petites opérations pour effectuer diverses tâches de filtrage et de comptage. Chacun a son propre style - certains aiment awket sedcertains aiment cutet tr. Voici comment je le ferais:

Pour traiter un nom de fichier particulier:

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

ou comme filtre:

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

Cela fonctionne comme ceci:

  1. od -a sépare le fichier en caractères ASCII.
  2. cut -b 9-élimine le préfixe odmet.
  3. tr " " \\n convertit les espaces entre les caractères en nouvelles lignes afin qu'il y ait un caractère par ligne.
  4. egrep -v "^$" se débarrasse de toutes les lignes vides supplémentaires que cela crée.
  5. sort rassemble les occurrences de chaque personnage.
  6. uniq -c compte le nombre de répétitions de chaque ligne.

Je l'ai nourri "Bonjour tout le monde!" suivi d'une nouvelle ligne et obtenu ceci:

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

9

La sedpartie étant basée sur la réponse de @ Guru , voici une autre approche utilisant uniq, similaire à la solution de 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
Utilisez [[:alpha:]]plutôt que .dans sedpour faire correspondre uniquement les caractères et non les nouvelles lignes.
Claudius

1
[[:alpha:]]échouera si vous essayez également de faire correspondre des choses du genre -, ce qui a été mentionné dans la question
Izkata

Correct. Il pourrait être plus agréable d'ajouter une deuxième expression à sed d'abord filtrer tout le reste, puis correspondre explicitement sur les caractères souhaités: sed -e 's/[^ATCGN-]//g' -e 's/\([ATCGN-]\)/\1\n/g' foo | sort | uniq -c. Cependant, je ne sais pas comment me débarrasser des nouvelles lignes: \
Claudius

7

Vous pouvez combiner grepet wcfaire ceci:

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

greprecherche dans le (s) fichier (s) donné (s) le texte spécifié et l' -ooption lui indique d'imprimer uniquement les correspondances réelles (c'est-à-dire les caractères recherchés), plutôt que le paramètre par défaut qui consiste à imprimer chaque ligne dans laquelle le texte de recherche était trouvé sur.

wcaffiche le nombre d'octets, de mots et de lignes pour chaque fichier ou, dans ce cas, la sortie de la grepcommande. L' -woption lui dit de compter les mots, chaque mot étant une occurrence de votre caractère de recherche. Bien sûr, l' -loption (qui compte les lignes) fonctionnerait également, car grepchaque occurrence de votre caractère de recherche est imprimée sur une ligne distincte.

Pour faire cela pour un nombre de caractères à la fois, placez les caractères dans un tableau et passez-le en boucle:

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

Exemple: pour un fichier contenant la chaîne TGC-GTCCNATGCGNNTCACANN-, le résultat serait:

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

Pour plus d'informations, voir man grepet man wc.


L'inconvénient de cette approche, comme le note l'utilisateur Journeyman Geek ci-dessous, est qu'il grepdoit être exécuté une fois pour chaque personnage. En fonction de la taille de vos fichiers, cela peut entraîner une baisse notable des performances. En revanche, lorsque vous avez terminé, il est un peu plus facile de voir rapidement quels caractères sont recherchés et de les ajouter / supprimer, car ils sont sur une ligne distincte du reste du code.


3
ils auraient besoin de le répéter par le type de personnage qu'ils veulent ... j'ajouterais. Je pourrais jurer qu'il y a une solution plus élégante, mais il faut plus de fouilles; p
Journeyman Geek

@JourneymanGeek Bon point. Une approche qui vient à l’esprit est de placer les personnages dans un tableau et de le parcourir en boucle. J'ai mis à jour mon post.
Indrek

OMI trop complexe. Il suffit d'utiliser grep -ea -et et ainsi de suite. Si vous le placez dans un tableau et que vous le parcourez en boucle, ne devez-vous pas exécuter le cycle grep une fois par caractère?
Journeyman Geek

@JourneymanGeek Vous avez probablement raison. uniq -csemble également être un meilleur moyen d’obtenir une sortie bien formatée. Je ne suis pas un gourou * nix, ce qui précède est ce que j'ai réussi à rassembler à partir de mes connaissances limitées et de quelques pages de manuel :)
Indrek

Ainsi que moi; p, et l’un de mes mandats précédents a consisté à trier environ 5 000 entrées de carnet d’adresses, ce qui a été grandement facilité par uniq.
Journeyman Geek

7

En utilisant les lignes de séquence de 22hgp10a.txt, la différence de temps entre grep et awk sur mon système fait en sorte que awk soit le chemin à parcourir ...

[Edit]: Après avoir vu la solution compilée de Dave, oubliez également awk, qui se termine en ~ 0,1 seconde sur ce fichier pour un comptage respectant la casse.

# 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 version de ghostdog insensible à la casse est terminée en 14 secondes environ.

Le sed est expliqué dans la réponse acceptée à cette question .
L'analyse comparative est comme dans la réponse acceptée à cette question .
La réponse acceptée par ghostdog74 était à cette question .


1
Vous pouvez s/cache[letters[x]]/cache[letters[x]]+cache[toupper(letters[x])]utiliser le mien pour le rendre insensible à la casse sans affecter sa vitesse.
Dave

6

Je pense que toute mise en œuvre décente évite de trier. Mais comme c'est aussi une mauvaise idée de tout lire 4 fois, je pense que l'on pourrait générer un flux qui passe par 4 filtres, un pour chaque caractère, qui est filtré et où les longueurs de flux sont également calculées.

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

Les sommes cumulées sont alors dans tmp [0-6] .txt .. donc le travail est toujours en cours

Dans cette approche, il n’ya que 13 canaux convertis en moins de 1 Mo de mémoire.
Bien sûr ma solution préférée est:

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

C'est une très bonne utilisation de tr.
adavid

4

Je ne connaissais uniqni de grep -o, mais étant donné que mes commentaires sur @JourneymanGeek et @ crazy2be avaient un tel soutien, peut - être que je devrais en faire un anwser de son propre:

Si vous savez qu'il n'y a que de "bons" caractères (ceux que vous voulez compter) dans votre fichier, vous pouvez aller chercher

grep . -o YourFile | sort | uniq -c

Si seulement certains caractères doivent être comptés et d’autres pas (séparateurs)

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

Le premier utilise le caractère générique d'expression régulière ., qui correspond à n'importe quel caractère. Le second utilise un "ensemble de caractères acceptés", sans ordre spécifique, sauf que celui-ci -doit venir en dernier ( A-Cest interprété comme "tout caractère entre Aet" C). Des guillemets sont nécessaires dans ce cas afin que votre shell n'essaie pas de le développer pour vérifier les fichiers à caractère unique le cas échéant (et génère une erreur "aucune correspondance" si aucun).

Notez que "sort" a aussi un -udrapeau nique pour ne rapporter que les choses une fois, mais aucun drapeau associé pour compter les doublons uniqest donc obligatoire.


-ne doit pas venir en dernier si vous y échappez avec une barre oblique inversée: cela '[A\-CTGN]'devrait fonctionner correctement.
Indrek

2

Un idiot:

tr -cd ATCGN- | iconv -f ascii -t ucs2 | tr '\0' '\n' | sort | uniq -c
  • trsupprimer ( -d) tous les caractères sauf ( -c) ATCGN-
  • iconv convertir en ucs2 (UTF16 limité à 2 octets) pour ajouter un octet 0 après chaque octet,
  • un autre trpour traduire ces caractères NUL en NL. Maintenant, chaque personnage est sur sa propre ligne
  • sort | uniq -ccompter chaque ligne uniq

C'est une alternative à l' -ooption grep non-standard (GNU) .


Pourriez-vous donner une brève explication des commandes et de la logique ici?
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 }'

Le format de sortie n'est pas le meilleur ...

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

Théorie de fonctionnement:

  • $ ({command | command} 2> tmp) redirige le stderr du flux vers un fichier temporaire.
  • dd sort stdin sur stdout et affiche le nombre d'octets passés à stderr
  • tr -d filtre un caractère à la fois
  • grep and sort filtre la sortie de dd en ordre décroissant
  • awk calcule la différence
  • Le tri est utilisé uniquement dans la phase de post-traitement pour traiter l’incertitude de l’ordre de sortie des instances de dd.

La vitesse semble être de 60 Mbps +


Améliorations: se débarrasser de tmp? utiliser 'coller' pour imprimer la lettre impliquée?
Aki Suihkonen

1

Exemple de fichier:

$ cat file
aix
unix
linux

Commander:

$ 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 pour manque de clarté et pour avoir posté une ligne sans explication. Autant que je sache, cela pourrait être une bombe fourchette
PPC

1

Combinant quelques autres

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

Ajouter | sort -nrpour voir les résultats par ordre de fréquence.


1

Réponse courte:

Si les circonstances le permettent, comparez les tailles de fichier des jeux de caractères faibles à celles ne contenant aucun caractère pour obtenir un décalage et compter simplement les octets.

Ah, mais les détails enchevêtrés:

Ce sont tous des personnages Ascii. Un octet par. Bien sûr, les fichiers contiennent des métadonnées supplémentaires pour une variété d'éléments utilisés par le système d'exploitation et l'application qui les a créés. Dans la plupart des cas, je m'attendrais à ce qu'ils occupent le même espace indépendamment des métadonnées, mais j'essayerais de maintenir des circonstances identiques lorsque vous testez d'abord l'approche, puis que vous vérifiez que vous disposez d'un décalage constant avant de ne pas vous en préoccuper. L’autre chose à faire est que les sauts de ligne impliquent généralement deux caractères d’espace blanc ascii et que chaque onglet ou espace correspond à un. Si vous pouvez être sûr qu'ils seront présents et qu'il n'y a aucun moyen de savoir combien d'avance, je cesserais de lire maintenant.

Cela peut sembler beaucoup de contraintes, mais si vous pouvez facilement les établir, cela me semble l’approche la plus facile / la plus performante si vous en avez beaucoup à regarder (ce qui semble probable si c’est de l’ADN). Contrôler la longueur d'une tonne de fichiers et soustraire une constante prendrait plus de temps que d'exécuter grep (ou similaire) sur chacun d'entre eux.

Si:

  • Ce sont de simples chaînes ininterrompues dans des fichiers texte purs
  • Ils sont dans des types de fichiers identiques créés par le même éditeur de texte vanilla non formateur que Scite (le collage est acceptable tant que vous vérifiez les espaces / retours) ou un programme de base écrit par quelqu'un

Et deux choses qui pourraient ne pas avoir d'importance mais que je testerais avec d'abord

  • Les noms de fichiers sont de même longueur
  • Les fichiers sont dans le même répertoire

Essayez de trouver le décalage en procédant comme suit:

Comparez un fichier vide à un fichier contenant quelques caractères facilement comptables, à un autre contenant quelques caractères. Si vous soustrayez le fichier vide des deux autres fichiers pour obtenir un nombre d'octets correspondant au nombre de caractères, vous avez terminé. Vérifiez les longueurs de fichier et soustrayez cette quantité vide. Si vous voulez essayer de comprendre des fichiers multilignes, la plupart des éditeurs associent deux caractères spéciaux d'un octet pour les sauts de ligne, l'un d'eux étant généralement ignoré, mais vous devrez au moins grep pour les caractères d'espace-blanc, auquel cas vous pourriez aussi bien tout faire avec grep.


1

Façon Haskell :

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

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

ça marche comme ça:

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
...

compiler et utiliser:

$ 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
...

pas bon pour les gros fichiers peut-être.


1

Rapide perl hack:

perl -nle 'while(/[ATCGN]/g){$a{$&}+=1};END{for(keys(%a)){print "$_:$a{$_}"}}'
  • -n: Parcourez les lignes d'entrée mais n'imprimez rien pour elles
  • -l: Supprimer ou ajouter des sauts de ligne automatiquement
  • while: itérer sur toutes les occurrences de vos symboles demandés dans la ligne en cours
  • END: À la fin, imprimer les résultats
  • %a: Hash où les valeurs sont stockées

Les caractères qui ne se produisent pas du tout ne seront pas inclus dans le résultat.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.