Construire un graphique ASCII des mots les plus couramment utilisés dans un texte donné [fermé]

156

Le défi:

Construisez un graphique ASCII des mots les plus couramment utilisés dans un texte donné.

Les règles:

  • N'acceptez a-zet A-Z(caractères alphabétiques) que dans le cadre d'un mot.
  • Ignorez le boîtier ( She== shepour notre propos).
  • Ignorez les mots suivants (assez arbitraires, je sais): the, and, of, to, a, i, it, in, or, is
  • Clarification: considérant don't: cela serait considéré comme 2 «mots» différents dans les plages a-zet A-Z: ( donet t).

  • Facultativement (il est trop tard pour modifier formellement les spécifications maintenant), vous pouvez choisir de supprimer tous les «mots» à une seule lettre (cela pourrait également réduire la liste des ignorés).

Analysez un donné text(lisez un fichier spécifié via des arguments de ligne de commande ou insérez-le; présume us-ascii) et construisez-nous un word frequency chartavec les caractéristiques suivantes:

  • Affichez le graphique (voir également l'exemple ci-dessous) pour les 22 mots les plus courants (classés par fréquence décroissante).
  • La barre widthreprésente le nombre d'occurrences (fréquence) du mot (proportionnellement). Ajoutez un espace et imprimez le mot.
  • Assurez-vous que ces barres (plus espace-mot-espace) correspondent toujours : bar+ [space]+ word+ [space]doit toujours être <= 80caractères (assurez-vous de prendre en compte les différentes longueurs de barre et de mot possibles: par exemple: le deuxième mot le plus courant pourrait être beaucoup plus long alors le premier tout en ne différant pas tellement en fréquence). Maximisez la largeur de la barre dans ces contraintes et mettez à l'échelle les barres de manière appropriée (en fonction des fréquences qu'elles représentent).

Un exemple:

Le texte de l'exemple peut être trouvé ici ( Alice's Adventures in Wonderland, par Lewis Carroll ).

Ce texte spécifique donnerait le graphique suivant:

 _________________________________________________________________________
| _________________________________________________________________________ | elle
| _______________________________________________________________ | tu
| ____________________________________________________________ | m'a dit
| ____________________________________________________ | Alice
| ______________________________________________ | était
| __________________________________________ | cette
| ___________________________________ | comme
| _______________________________ | sa
| ____________________________ | avec
| ____________________________ | à
| ___________________________ | s
| ___________________________ | t
| _________________________ | sur
| _________________________ | tout
| ______________________ | ce
| ______________________ | pour
| ______________________ | eu
| _____________________ | mais
| ____________________ | être
| ____________________ | ne pas
| ___________________ | ils
| __________________ | alors


Pour votre information: voici les fréquences sur lesquelles le tableau ci-dessus est construit:

[('elle', 553), ('vous', 481), ('a dit', 462), ('alice', 403), ('était', 358), ('que
', 330), (' as ', 274), (' her ', 248), (' with ', 227), (' at ', 227), (' s ', 219), (' t '
, 218), ('on', 204), ('all', 200), ('this', 181), ('for', 179), ('had', 178), ('
mais ', 175), (' être ', 167), (' pas ', 166), (' ils ', 155), (' so ', 152)]

Un deuxième exemple (pour vérifier si vous avez implémenté la spécification complète): remplacez chaque occurrence de youdans le fichier Alice in Wonderland lié par superlongstringstring:

 ________________________________________________________________
| ________________________________________________________________ | elle
| _______________________________________________________ | superlongstringstring
| _____________________________________________________ | m'a dit
| ______________________________________________ | Alice
| ________________________________________ | était
| _____________________________________ | cette
| ______________________________ | comme
| ___________________________ | sa
| _________________________ | avec
| _________________________ | à
| ________________________ | s
| ________________________ | t
| ______________________ | sur
| _____________________ | tout
| ___________________ | ce
| ___________________ | pour
| ___________________ | eu
| __________________ | mais
| _________________ | être
| _________________ | ne pas
| ________________ | ils
| ________________ | alors

Le gagnant:

Solution la plus courte (par nombre de caractères, par langue). S'amuser!


Edit : Tableau résumant les résultats à ce jour (15/02/2012) (initialement ajouté par l'utilisateur Nas Banov):

Langue Relaxed Strict
========= ======= ======
GolfScript 130 143
Perl 185
Windows PowerShell 148 199
Mathematica 199
Rubis 185205
Chaîne d'outils Unix 194228
Python 183 243
Clojure 282
Scala 311
Haskell 333
Awk 336
R 298
Javascript 304 354
Groovy 321
Matlab 404
C # 422
Smalltalk 386
450 PHP
F # 452
TSQL 483 507

Les nombres représentent la longueur de la solution la plus courte dans une langue spécifique. «Strict» fait référence à une solution qui implémente complètement la spécification (dessine des |____|barres, ferme la première barre en haut avec une ____ligne, tient compte de la possibilité de mots longs avec une fréquence élevée, etc.). «Relaxed» signifie que certaines libertés ont été prises pour se raccourcir en solution.

Seules les solutions plus courtes que 500 caractères sont incluses. La liste des langues est triée par la longueur de la solution «stricte». «Unix Toolchain» est utilisé pour désigner diverses solutions qui utilisent le shell * nix traditionnel plus un mélange d'outils (comme grep, tr, sort, uniq, head, perl, awk).

ChristopheD
la source
4
Eh bien, «la plus longue barre» + mot = 80 peut ne pas tenir dans les 80 cols si le deuxième mot le plus courant est un mot beaucoup plus long. Je recherche la «contrainte maximale», je suppose.
Brian
1
Normalisons-nous le boîtier? «Elle» = «elle»?
Brian
2
IMO faire cela performant, à la fois en termes de temps d'exécution et d'utilisation de la mémoire, semble être un défi plus intéressant que le nombre de caractères.
Frank Farmer
81
Je suis content de voir que mes mots préférés set tsont représentés.
indiv
8
@indiv, @Nas Banov - tokenizer idiot trop simple lit "n'a pas" comme {didn, t} et "elle est" comme {elle, s} :)
hobbs

Réponses:

123

LabVIEW 51 nœuds, 5 structures, 10 diagrammes

Apprendre à l'éléphant à claquettes n'est jamais joli. Je vais, ah, sauter le nombre de caractères.

code labVIEW

résultats

Le programme se déroule de gauche à droite:

Code labVIEW expliqué

Joe Zoller
la source
10
Ça n'en vaut pas la peine
4
LabVIEW est très heureux dans sa niche de contrôle matériel et de mesure, mais vraiment assez horrible pour la manipulation de cordes.
Joe Z
19
Meilleure réponse de golf de code que j'ai vue. +1 pour sortir des sentiers battus!
Blair Holloway
1
Je dois compter les éléments pour nous ... chaque boîte et chaque widget que vous avez dû faire glisser à l'écran compte.
dmckee --- ex-moderator chaton
1
Serait-il possible d'ajouter un lien vers une version plus grande de ces graphiques?
Svish
42

Ruby 1.9, 185 caractères

(fortement basé sur les autres solutions Ruby)

w=($<.read.downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).group_by{|x|x}.map{|x,y|[-y.size,x]}.sort[0,22]
k,l=w[0]
puts [?\s+?_*m=76-l.size,w.map{|f,x|?|+?_*(f*m/k)+"| "+x}]

Au lieu d'utiliser des commutateurs de ligne de commande comme les autres solutions, vous pouvez simplement passer le nom de fichier comme argument. (ie ruby1.9 wordfrequency.rb Alice.txt)

Puisque j'utilise des caractères littéraux ici, cette solution ne fonctionne que dans Ruby 1.9.

Edit: Remplacement des points-virgules par des sauts de ligne pour «lisibilité». : P

Edit 2: Shtééf a fait remarquer que j'avais oublié l'espace de fin - corrigé ça.

Edit 3: Suppression de l'espace de fin à nouveau;)

Ventero
la source
Il manque l'espace de fin, après chaque mot.
Stéphan Kochen
Aww shoot, ne tenez pas compte de cela. On dirait que le golf vient d'être mis à jour, l'espace de fuite n'est plus nécessaire. :)
Stéphan Kochen
Ne semble-t-il pas convenir au «superlongstringstring» en 2e position ou plus tard? (voir la description du problème)
Nas Banov
2
Cela semble vraiment maintenable.
Zombies
39

GolfScript, 177 175 173 167 164 163 144 131 130 caractères

Lent - 3 minutes pour l'exemple de texte (130)

{32|.123%97<n@if}%]''*n%"oftoitinorisa"2/-"theandi"3/-$(1@{.3$>1{;)}if}/]2/{~~\;}$22<.0=~:2;,76\-:1'_':0*' '\@{"
|"\~1*2/0*'| '@}/

Explication:

{           #loop through all characters
 32|.       #convert to uppercase and duplicate
 123%97<    #determine if is a letter
 n@if       #return either the letter or a newline
}%          #return an array (of ints)
]''*        #convert array to a string with magic
n%          #split on newline, removing blanks (stack is an array of words now)
"oftoitinorisa"   #push this string
2/          #split into groups of two, i.e. ["of" "to" "it" "in" "or" "is" "a"]
-           #remove any occurrences from the text
"theandi"3/-#remove "the", "and", and "i"
$           #sort the array of words
(1@         #takes the first word in the array, pushes a 1, reorders stack
            #the 1 is the current number of occurrences of the first word
{           #loop through the array
 .3$>1{;)}if#increment the count or push the next word and a 1
}/
]2/         #gather stack into an array and split into groups of 2
{~~\;}$     #sort by the latter element - the count of occurrences of each word
22<         #take the first 22 elements
.0=~:2;     #store the highest count
,76\-:1     #store the length of the first line
'_':0*' '\@ #make the first line
{           #loop through each word
"
|"\~        #start drawing the bar
1*2/0       #divide by zero
*'| '@      #finish drawing the bar
}/

"Correct" (espérons-le). (143)

{32|.123%97<n@if}%]''*n%"oftoitinorisa"2/-"theandi"3/-$(1@{.3$>1{;)}if}/]2/{~~\;}$22<..0=1=:^;{~76@,-^*\/}%$0=:1'_':0*' '\@{"
|"\~1*^/0*'| '@}/

Moins lent - une demi-minute. (162)

'"'/' ':S*n/S*'"#{%q
'\+"
.downcase.tr('^a-z','
')}\""+~n%"oftoitinorisa"2/-"theandi"3/-$(1@{.3$>1{;)}if}/]2/{~~\;}$22<.0=~:2;,76\-:1'_':0*S\@{"
|"\~1*2/0*'| '@}/

Sortie visible dans les journaux de révision.

Nabb
la source
2
À propos de GolfScript: golfscript.com/golfscript
Assaf Lavie
2
Pas correct, en ce sens que si le deuxième mot est vraiment long, il passera à la ligne suivante.
Gabe
5
"diviser par zéro" ... GolfScript le permet?
JAB
35

206

shell, grep, tr, grep, tri, uniq, tri, tête, perl

~ % wc -c wfg
209 wfg
~ % cat wfg
egrep -oi \\b[a-z]+|tr A-Z a-z|egrep -wv 'the|and|of|to|a|i|it|in|or|is'|sort|uniq -c|sort -nr|head -22|perl -lape'($f,$w)=@F;$.>1or($q,$x)=($f,76-length$w);$b="_"x($f/$q*$x);$_="|$b| $w ";$.>1or$_=" $b\n$_"'
~ % # usage:
~ % sh wfg < 11.txt

hm, juste vu ci-dessus: sort -nr-> sort -npuis head-> tail=> 208 :)
update2: euh, bien sûr, ce qui précède est idiot, car il sera alors inversé. Donc, 209.
update3: optimisation de l'expression rationnelle d'exclusion -> 206

egrep -oi \\b[a-z]+|tr A-Z a-z|egrep -wv 'the|and|o[fr]|to|a|i[tns]?'|sort|uniq -c|sort -nr|head -22|perl -lape'($f,$w)=@F;$.>1or($q,$x)=($f,76-length$w);$b="_"x($f/$q*$x);$_="|$b| $w ";$.>1or$_=" $b\n$_"'



pour le plaisir, voici une version uniquement perl (beaucoup plus rapide):

~ % wc -c pgolf
204 pgolf
~ % cat pgolf
perl -lne'$1=~/^(the|and|o[fr]|to|.|i[tns])$/i||$f{lc$1}++while/\b([a-z]+)/gi}{@w=(sort{$f{$b}<=>$f{$a}}keys%f)[0..21];$Q=$f{$_=$w[0]};$B=76-y///c;print" "."_"x$B;print"|"."_"x($B*$f{$_}/$Q)."| $_"for@w'
~ % # usage:
~ % sh pgolf < 11.txt
Stor
la source
35

Transact SQL set solution basée sur (SQL Server 2005) 1063 892 873 853 827 820 783 683 647 644 630 caractères

Merci à Gabe pour quelques suggestions utiles pour réduire le nombre de caractères.

NB: Les sauts de ligne ajoutés pour éviter les barres de défilement, seul le dernier saut de ligne est requis.

DECLARE @ VARCHAR(MAX),@F REAL SELECT @=BulkColumn FROM OPENROWSET(BULK'A',
SINGLE_BLOB)x;WITH N AS(SELECT 1 i,LEFT(@,1)L UNION ALL SELECT i+1,SUBSTRING
(@,i+1,1)FROM N WHERE i<LEN(@))SELECT i,L,i-RANK()OVER(ORDER BY i)R INTO #D
FROM N WHERE L LIKE'[A-Z]'OPTION(MAXRECURSION 0)SELECT TOP 22 W,-COUNT(*)C
INTO # FROM(SELECT DISTINCT R,(SELECT''+L FROM #D WHERE R=b.R FOR XML PATH
(''))W FROM #D b)t WHERE LEN(W)>1 AND W NOT IN('the','and','of','to','it',
'in','or','is')GROUP BY W ORDER BY C SELECT @F=MIN(($76-LEN(W))/-C),@=' '+
REPLICATE('_',-MIN(C)*@F)+' 'FROM # SELECT @=@+' 
|'+REPLICATE('_',-C*@F)+'| '+W FROM # ORDER BY C PRINT @

Version lisible

DECLARE @  VARCHAR(MAX),
        @F REAL
SELECT @=BulkColumn
FROM   OPENROWSET(BULK'A',SINGLE_BLOB)x; /*  Loads text file from path
                                             C:\WINDOWS\system32\A  */

/*Recursive common table expression to
generate a table of numbers from 1 to string length
(and associated characters)*/
WITH N AS
     (SELECT 1 i,
             LEFT(@,1)L

     UNION ALL

     SELECT i+1,
            SUBSTRING(@,i+1,1)
     FROM   N
     WHERE  i<LEN(@)
     )
  SELECT   i,
           L,
           i-RANK()OVER(ORDER BY i)R
           /*Will group characters
           from the same word together*/
  INTO     #D
  FROM     N
  WHERE    L LIKE'[A-Z]'OPTION(MAXRECURSION 0)
             /*Assuming case insensitive accent sensitive collation*/

SELECT   TOP 22 W,
         -COUNT(*)C
INTO     #
FROM     (SELECT DISTINCT R,
                          (SELECT ''+L
                          FROM    #D
                          WHERE   R=b.R FOR XML PATH('')
                          )W
                          /*Reconstitute the word from the characters*/
         FROM             #D b
         )
         T
WHERE    LEN(W)>1
AND      W NOT IN('the',
                  'and',
                  'of' ,
                  'to' ,
                  'it' ,
                  'in' ,
                  'or' ,
                  'is')
GROUP BY W
ORDER BY C

/*Just noticed this looks risky as it relies on the order of evaluation of the 
 variables. I'm not sure that's guaranteed but it works on my machine :-) */
SELECT @F=MIN(($76-LEN(W))/-C),
       @ =' '      +REPLICATE('_',-MIN(C)*@F)+' '
FROM   #

SELECT @=@+' 
|'+REPLICATE('_',-C*@F)+'| '+W
             FROM     #
             ORDER BY C

PRINT @

Production

 _________________________________________________________________________ 
|_________________________________________________________________________| she
|_______________________________________________________________| You
|____________________________________________________________| said
|_____________________________________________________| Alice
|_______________________________________________| was
|___________________________________________| that
|____________________________________| as
|________________________________| her
|_____________________________| at
|_____________________________| with
|__________________________| on
|__________________________| all
|_______________________| This
|_______________________| for
|_______________________| had
|_______________________| but
|______________________| be
|_____________________| not
|____________________| they
|____________________| So
|___________________| very
|__________________| what

Et avec la longue corde

 _______________________________________________________________ 
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| Alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| at
|_________________________| with
|_______________________| on
|______________________| all
|____________________| This
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| So
|________________| very
|________________| what
Martin Smith
la source
12
Je vous ai donné un +1 parce que vous l'avez fait dans T-SQL, et pour citer Team America - "Vous avez des balles. J'aime les balles."
J'ai pris la liberté de convertir certains espaces en nouvelles lignes pour le rendre plus lisible. J'espère que je n'ai pas gâché les choses. Je l'ai également minifié un peu plus.
Gabe le
3
Ce code me crie dessus! : O
Joey
1
Une bonne façon d’enregistrer est de passer 0.000à juste 0, puis d’utiliser -Cau lieu de 1.0/C. Et faire FLOATen REALsauvera aussi un coup. Le plus important, cependant, est qu'il semble que vous ayez beaucoup d' ASinstances qui devraient être facultatives.
Gabe
1
OK, que diriez-vous SELECT [ ] FROM (SELECT $0 O, ' '+REPLICATE('_', MAX(C)*@F)+' ' [ ] FROM # UNION SELECT $1/C, '|'+REPLICATE('_',C*@F)+'| '+W FROM #)X ORDER BY O?
Gabe le
34

Ruby 207 213 211 210 207 203 201 200 caractères

Une amélioration sur Anurag, incorporant la suggestion de rfusca. Supprime également l'argument à trier et quelques autres golfs mineurs.

w=(STDIN.read.downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).group_by{|x|x}.map{|x,y|[-y.size,x]}.sort.take 22;k,l=w[0];m=76.0-l.size;puts' '+'_'*m;w.map{|f,x|puts"|#{'_'*(m*f/k)}| #{x} "}

Exécuter en tant que:

ruby GolfedWordFrequencies.rb < Alice.txt

Edit: remettre 'met', doit être là pour éviter d'avoir des guillemets en sortie.
Edit2: Changed File-> IO
Edit3: supprimé / i
Edit4: Suppression des parenthèses autour de (f * 1.0), racontée
Edit5: Utilisez l'ajout de chaîne pour la première ligne; se développer ssur place.
Edit6: Made m float, supprimé 1.0. EDIT: ne fonctionne pas, change de longueur. EDIT: pas pire qu'avant
Edit7: utiliser STDIN.read.

archgoon
la source
+1 - j'adore la partie de tri, très intelligent :)
Anurag
Hé, petite optimisation par rapport à l'essentiel de celui-ci en premier lieu. :)
archgoon
Agréable! Ajout de deux des modifications que j'ai également apportées à la version d'Anurag. Rase un autre 4.
Stéphan Kochen
La solution a dévié de la sortie d'origine, je vais essayer et comprendre où cela s'est passé.
archgoon
1
Il existe une variante plus courte de cela plus bas.
archgoon
28

Mathematica ( 297 284 248 244 242 199) caractères pur fonctionnel

et Test de la loi de Zipf

Regarde maman ... pas de vars, pas de mains, pas de tête

Edit 1> quelques raccourcis définis (284 caractères)

f[x_, y_] := Flatten[Take[x, All, y]]; 

BarChart[f[{##}, -1], 
         BarOrigin -> Left, 
         ChartLabels -> Placed[f[{##}, 1], After], 
         Axes -> None
] 
& @@
Take[
  SortBy[
     Tally[
       Select[
        StringSplit[ToLowerCase[Import[i]], RegularExpression["\\W+"]], 
       !MemberQ[{"the", "and", "of", "to", "a", "i", "it", "in", "or","is"}, #]&]
     ], 
  Last], 
-22]

Quelques explications

Import[] 
   # Get The File

ToLowerCase []
   # To Lower Case :)

StringSplit[ STRING , RegularExpression["\\W+"]]
   # Split By Words, getting a LIST

Select[ LIST, !MemberQ[{LIST_TO_AVOID}, #]&]
   #  Select from LIST except those words in LIST_TO_AVOID
   #  Note that !MemberQ[{LIST_TO_AVOID}, #]& is a FUNCTION for the test

Tally[LIST]
   # Get the LIST {word,word,..} 
     and produce another  {{word,counter},{word,counter}...}

SortBy[ LIST ,Last]
   # Get the list produced bt tally and sort by counters
     Note that counters are the LAST element of {word,counter}

Take[ LIST ,-22]
   # Once sorted, get the biggest 22 counters

BarChart[f[{##}, -1], ChartLabels -> Placed[f[{##}, 1], After]] &@@ LIST
   # Get the list produced by Take as input and produce a bar chart

f[x_, y_] := Flatten[Take[x, All, y]]
   # Auxiliary to get the list of the first or second element of lists of lists x_
     dependending upon y
   # So f[{##}, -1] is the list of counters
   # and f[{##}, 1] is the list of words (labels for the chart)

Production

texte alternatif http://i49.tinypic.com/2n8mrer.jpg

Mathematica n'est pas bien adapté pour le golf, et c'est simplement à cause des noms de fonctions longs et descriptifs. Des fonctions comme "RegularExpression []" ou "StringSplit []" me font juste sangloter :(.

Test de la loi de Zipf

La loi de Zipf prédit que pour un texte en langage naturel, le tracé Log (Rang) vs Log (occurrences) suit une relation linéaire .

La loi est utilisée dans le développement d'algorithmes pour la criptographie et la compression de données. (Mais ce n'est PAS le "Z" dans l'algorithme LZW).

Dans notre texte, nous pouvons le tester avec ce qui suit

 f[x_, y_] := Flatten[Take[x, All, y]]; 
 ListLogLogPlot[
     Reverse[f[{##}, -1]], 
     AxesLabel -> {"Log (Rank)", "Log Counter"}, 
     PlotLabel -> "Testing Zipf's Law"]
 & @@
 Take[
  SortBy[
    Tally[
       StringSplit[ToLowerCase[b], RegularExpression["\\W+"]]
    ], 
   Last],
 -1000]

Le résultat est (plutôt bien linéaire)

texte alternatif http://i46.tinypic.com/33fcmdk.jpg

Modifier 6> (242 caractères)

Refactorisation de l'expression régulière (plus de fonction Select)
Suppression de mots de 1 caractère
Définition plus efficace de la fonction "f"

f = Flatten[Take[#1, All, #2]]&; 
BarChart[
     f[{##}, -1], 
     BarOrigin -> Left, 
     ChartLabels -> Placed[f[{##}, 1], After], 
     Axes -> None] 
& @@
  Take[
    SortBy[
       Tally[
         StringSplit[ToLowerCase[Import[i]], 
          RegularExpression["(\\W|\\b(.|the|and|of|to|i[tns]|or)\\b)+"]]
       ],
    Last],
  -22]

Modifier 7 → 199 caractères

BarChart[#2, BarOrigin->Left, ChartLabels->Placed[#1, After], Axes->None]&@@ 
  Transpose@Take[SortBy[Tally@StringSplit[ToLowerCase@Import@i, 
    RegularExpression@"(\\W|\\b(.|the|and|of|to|i[tns]|or)\\b)+"],Last], -22]
  • Remplacé fpar les arguments Transposeet Slot( #1/ #2).
  • Nous n'avons pas besoin de parenthèses puantes (utilisez f@xplutôt que f[x]si possible)

Bélisaire
la source
9
Vous pensez que "RegularExpression" est mauvais? J'ai pleuré quand j'ai tapé "System.Text.RegularExpressions.Regex.Split" dans la version C #, jusqu'à ce que j'aie vu le code Objective-C: "stringWithContentsOfFile", "enumerateSubstringsInRange", "NSStringEnumerationByWords", "sortedArrayUsing etComparateur .
Gabe le
2
@Gabe Merci ... Je me sens mieux maintenant. En espagnol, nous disons "mal de muchos, consuelo de tontos" .. Quelque chose comme "Beaucoup de troubles, fous soulagés": D
Dr. belisarius
1
Le |i|est redondant dans votre regex car vous l'avez déjà .|.
Gabe le
1
J'aime ce dicton espagnol. La chose la plus proche à laquelle je puisse penser en anglais est "la misère aime la compagnie". Voici ma tentative de traduction: "C'est un imbécile qui, lorsqu'il souffre, se console à penser aux autres dans la même situation." Un travail incroyable sur l'implémentation de Mathematica, btw.
dreeves le
@dreeves Foolishness dépasse facilement la barrière de la langue ... Heureux de vous voir aimer mon petit programme Mathematica, je commence tout juste à apprendre la langue
Dr. belisarius
26

C # - 510 451 436 446 434 426 422 caractères (minified)

Pas si court, mais maintenant probablement correct! Notez que la version précédente n'affichait pas la première ligne des barres, ne mettait pas à l'échelle les barres correctement, téléchargeait le fichier au lieu de l'obtenir à partir de stdin et n'incluait pas toute la verbosité C # requise. Vous pourriez facilement raser de nombreux traits si C # n'avait pas besoin de tant de merde supplémentaire. Peut-être que Powershell pourrait faire mieux.

using C=System.Console;   // alias for Console
using System.Linq;  // for Split, GroupBy, Select, OrderBy, etc.

class Class // must define a class
{
    static void Main()  // must define a Main
    {
        // split into words
        var allwords = System.Text.RegularExpressions.Regex.Split(
                // convert stdin to lowercase
                C.In.ReadToEnd().ToLower(),
                // eliminate stopwords and non-letters
                @"(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|\W)+")
            .GroupBy(x => x)    // group by words
            .OrderBy(x => -x.Count()) // sort descending by count
            .Take(22);   // take first 22 words

        // compute length of longest bar + word
        var lendivisor = allwords.Max(y => y.Count() / (76.0 - y.Key.Length));

        // prepare text to print
        var toPrint = allwords.Select(x=> 
            new { 
                // remember bar pseudographics (will be used in two places)
                Bar = new string('_',(int)(x.Count()/lendivisor)), 
                Word=x.Key 
            })
            .ToList();  // convert to list so we can index into it

        // print top of first bar
        C.WriteLine(" " + toPrint[0].Bar);
        toPrint.ForEach(x =>  // for each word, print its bar and the word
            C.WriteLine("|" + x.Bar + "| " + x.Word));
    }
}

422 caractères avec lentiviseur en ligne (ce qui le rend 22 fois plus lent) sous la forme ci-dessous (retours à la ligne utilisés pour certains espaces):

using System.Linq;using C=System.Console;class M{static void Main(){var
a=System.Text.RegularExpressions.Regex.Split(C.In.ReadToEnd().ToLower(),@"(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|\W)+").GroupBy(x=>x).OrderBy(x=>-x.Count()).Take(22);var
b=a.Select(x=>new{p=new string('_',(int)(x.Count()/a.Max(y=>y.Count()/(76d-y.Key.Length)))),t=x.Key}).ToList();C.WriteLine(" "+b[0].p);b.ForEach(x=>C.WriteLine("|"+x.p+"| "+x.t));}}
Gabe
la source
+1 pour le smart-ass téléchargeant le fichier en ligne. :)
sarnold
1
Volez l'URL courte de la réponse de Matt.
indiv
2
La spécification dit que le fichier doit être envoyé ou passé en tant qu'args. Si vous supposiez que args [0] contenait le nom du fichier local, vous pourriez le raccourcir considérablement en utilisant args [0] au lieu de (new WebClient ()). DownloadString (@ " gutenberg.org/files/11/11. txt " ) -> cela vous ferait gagner environ 70 caractères
thorkia
1
Voici une version remplaçant l'appel WebClient par args 0, un appel à StreamReader et supprimant quelques espaces supplémentaires. Nombre total de caractères = 413 var a = Regex.Replace ((new StreamReader (args [0])). ReadToEnd (), "[^ a-zA-Z]", "") .ToLower (). Split ('' ) .Where (x =>! (Nouveau [] {"le", "et", "de", "à", "a", "i", "il", "dans", "ou", " is "}). Contient (x)). GroupBy (x => x) .Select (g => new {w = g.Key, c = g.Count ()}). OrderByDescending (x => xc). Skip (1) .Take (22) .ToList (); var m = a.OrderByDescending (x => xc) .First (); a.ForEach (x => Console.WriteLine ("|" + new String (' _ ', xc * (80-mwLongueur-4) / mc) + "|" + xw));
thorkia
"new StreamReader" sans "using" est sale. File.ReadAllText (args [0]) ou Console.In.ReadToEnd () sont bien meilleurs. Dans ce dernier cas, vous pouvez même supprimer l'argument de votre Main (). :)
Rotsor
25

Perl, 237 229 209 caractères

(Mis à jour à nouveau pour battre la version Ruby avec des tours de golf plus sales, en remplaçant split/[^a-z/,lcavec lc=~/[a-z]+/g, et en éliminant un chèque de chaîne vide dans un autre endroit. Ceux - ci ont été inspirés par la version Ruby, donc le crédit où le crédit est dû.)

Mise à jour: maintenant avec Perl 5.10! Remplacez printpar sayet utilisez ~~pour éviter un map. Cela doit être appelé sur la ligne de commande en tant que perl -E '<one-liner>' alice.txt. Puisque le script entier est sur une seule ligne, l'écrire en une seule ligne ne devrait pas présenter de difficulté :).

 @s=qw/the and of to a i it in or is/;$c{$_}++foreach grep{!($_~~@s)}map{lc=~/[a-z]+/g}<>;@s=sort{$c{$b}<=>$c{$a}}keys%c;$f=76-length$s[0];say" "."_"x$f;say"|"."_"x($c{$_}/$c{$s[0]}*$f)."| $_ "foreach@s[0..21];

Notez que cette version se normalise pour le cas. Cela ne raccourcit pas la solution, car la suppression ,lc(pour le cas inférieur) vous oblige à ajouter A-Zà l'expression régulière fractionnée, donc c'est un lavage.

Si vous êtes sur un système où une nouvelle ligne est un caractère et non deux, vous pouvez la raccourcir de deux autres caractères en utilisant une nouvelle ligne littérale à la place de \n. Cependant, je n'ai pas écrit l'exemple ci-dessus de cette façon, car c'est "plus clair" (ha!) De cette façon.


Voici une solution perl généralement correcte, mais pas assez courte:

use strict;
use warnings;

my %short = map { $_ => 1 } qw/the and of to a i it in or is/;
my %count = ();

$count{$_}++ foreach grep { $_ && !$short{$_} } map { split /[^a-zA-Z]/ } (<>);
my @sorted = (sort { $count{$b} <=> $count{$a} } keys %count)[0..21];
my $widest = 76 - (length $sorted[0]);

print " " . ("_" x $widest) . "\n";
foreach (@sorted)
{
    my $width = int(($count{$_} / $count{$sorted[0]}) * $widest);
    print "|" . ("_" x $width) . "| $_ \n";
}

Ce qui suit est à peu près aussi court que possible tout en restant relativement lisible. (392 caractères).

%short = map { $_ => 1 } qw/the and of to a i it in or is/;
%count;

$count{$_}++ foreach grep { $_ && !$short{$_} } map { split /[^a-z]/, lc } (<>);
@sorted = (sort { $count{$b} <=> $count{$a} } keys %count)[0..21];
$widest = 76 - (length $sorted[0]);

print " " . "_" x $widest . "\n";
print"|" . "_" x int(($count{$_} / $count{$sorted[0]}) * $widest) . "| $_ \n" foreach @sorted;
JSB ձոգչ
la source
A quelques bugs en ce moment; fixation et raccourcissement.
JSB ձոգչ
4
Cela ne couvre pas le cas où le deuxième mot est beaucoup plus long que le premier, non?
Joey
1
Les deux foreachs peuvent être écrits comme l' forart. C'est 8 caractères plus bas. Ensuite, vous avez le grep{!($_~~@s)}map{lc=~/[a-z]+/g}<>, qui, je crois, pourrait être écrit de manière grep{!(/$_/i~~@s)}<>=~/[a-z]+/gà 4 descendre davantage. Remplacez le " "par $"et vous êtes en baisse 1 de plus ...
Zaid
sort{$c{$b}-$c{$a}}...pour en sauver deux de plus. Vous pouvez également passer juste au %clieu de keys %cla sortfonction et sauver quatre autres.
mob
20

Windows PowerShell, 199 caractères

$x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *
filter f($w){' '+'_'*$w
$x[-1..-22]|%{"|$('_'*($w*$_.Count/$x[-1].Count))| "+$_.Name}}
f(76..1|?{!((f $_)-match'.'*80)})[0]

(Le dernier saut de ligne n'est pas nécessaire, mais inclus ici pour plus de lisibilité.)

(Code actuel et mes fichiers de test disponibles dans mon référentiel SVN . J'espère que mes cas de test détectent les erreurs les plus courantes (longueur de la barre, problèmes de correspondance regex et quelques autres))

Hypothèses:

  • US ASCII en entrée. Cela devient probablement bizarre avec Unicode.
  • Au moins deux mots non-stop dans le texte

L'histoire

Version détendue (137), puisque cela est compté séparément maintenant, apparemment:

($x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *)[-1..-22]|%{"|$('_'*(76*$_.Count/$x[-1].Count))| "+$_.Name}
  • ne ferme pas la première barre
  • ne tient pas compte de la longueur du mot autre que le premier mot

Les variations des longueurs de barre d'un caractère par rapport à d'autres solutions sont dues au fait que PowerShell utilise l'arrondi au lieu de la troncature lors de la conversion des nombres à virgule flottante en nombres entiers. Étant donné que la tâche ne nécessitait qu'une longueur de barre proportionnelle, cela devrait être bien, cependant.

Par rapport à d'autres solutions, j'ai adopté une approche légèrement différente pour déterminer la longueur de barre la plus longue en essayant simplement et en prenant la longueur la plus élevée où aucune ligne ne dépasse 80 caractères.

Une version plus ancienne expliquée peut être trouvée ici .

Јοеу
la source
Impressionnant, semble Powershell est un environnement approprié pour le golf. Votre approche compte tenu de la longueur de la barre est exactement ce que j'ai essayé de décrire (pas si brillamment, je l'admets) dans les spécifications.
ChristopheD
1
@ChristopheD: D'après mon expérience (Anarchy Golf, certaines tâches de Project Euler et d'autres tâches juste pour le plaisir), PowerShell n'est généralement que légèrement pire que Ruby et souvent lié ou meilleur que Perl et Python. Pas de match pour GolfScript, cependant. Mais pour autant que je puisse voir, c'est peut-être la solution la plus courte qui tienne correctement compte des longueurs de barre ;-)
Joey
Apparemment, j'avais raison. Powershell peut faire mieux - beaucoup mieux! Veuillez fournir une version étendue avec des commentaires.
Gabe
Johannes: Avez-vous essayé -split("\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z]")? Ça marche pour moi.
Gabe
N'oubliez pas d'interpoler la chaîne de sortie: "|$('_'*($w*$_.count/$x[0].count))| $($_.name) "(ou d'éliminer le dernier espace, car c'est en quelque sorte automatique). Et vous pouvez utiliser -split("(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z])+")pour en enregistrer quelques autres en n'incluant pas les blancs (ou l'utilisation [-2..-23]).
Gabe
19

Rubis, 215, 216 , 218 , 221 , 224 , 236 , 237 caractères

mise à jour 1: Hourra ! C'est un lien avec la solution de JS Bangs . Je ne peux plus penser à un moyen de réduire plus :)

mise à jour 2: joué un sale tour de golf. Changé eachpour mapenregistrer 1 caractère :)

mise à jour 3: changé File.readen IO.read+2. Array.group_byn'était pas très fructueux, changé en reduce+6. La vérification insensible à la casse n'est pas nécessaire après la casse inférieure avec downcasedans regex +1. Le tri par ordre décroissant se fait facilement en annulant la valeur +6. Économies totales +15

mise à jour 4: [0]plutôt que .first, +3. (@ Shtééf)

mise à jour 5: Développer la variable lsur place, +1. Développer la variable ssur place, +2. (@ Shtééf)

mise à jour 6: utilisez l'addition de chaîne plutôt que l'interpolation pour la première ligne, +2. (@ Shtééf)

w=(IO.read($_).downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).reduce(Hash.new 0){|m,o|m[o]+=1;m}.sort_by{|k,v|-v}.take 22;m=76-w[0][0].size;puts' '+'_'*m;w.map{|x,f|puts"|#{'_'*(f*1.0/w[0][1]*m)}| #{x} "}

mise à jour 7: J'ai traversé un tas de battages pour détecter la première itération à l' intérieur de la boucle, en utilisant des variables d'instance. Tout ce que j'ai, c'est +1, bien qu'il y ait peut-être du potentiel. Préserver la version précédente, car je crois que celle-ci est de la magie noire. (@ Shtééf)

(IO.read($_).downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).reduce(Hash.new 0){|m,o|m[o]+=1;m}.sort_by{|k,v|-v}.take(22).map{|x,f|@f||(@f=f;puts' '+'_'*(@m=76-x.size));puts"|#{'_'*(f*1.0/@f*@m)}| #{x} "}

Version lisible

string = File.read($_).downcase

words = string.scan(/[a-z]+/i)
allowed_words = words - %w{the and of to a i it in or is}
sorted_words = allowed_words.group_by{ |x| x }.map{ |x,y| [x, y.size] }.sort{ |a,b| b[1] <=> a[1] }.take(22)
highest_frequency = sorted_words.first
highest_frequency_count = highest_frequency[1]
highest_frequency_word = highest_frequency[0]

word_length = highest_frequency_word.size
widest = 76 - word_length

puts " #{'_' * widest}"    
sorted_words.each do |word, freq|
  width = (freq * 1.0 / highest_frequency_count) * widest
  puts "|#{'_' * width}| #{word} "
end

Utiliser:

echo "Alice.txt" | ruby -ln GolfedWordFrequencies.rb

Production:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
Anurag
la source
3
"P" n'est-il pas un raccourci pour "met"? Cela pourrait en raser quelques-uns.
rfusca
1
Agréable. Votre utilisation de scan, cependant, m'a donné une meilleure idée, alors j'ai pris de l'avance :).
JSB ձոգչ
2
Vous devez mettre les barres à l'échelle de sorte que le mot le plus long et sa barre tiennent sur 80 caractères. Comme Brian l'a suggéré, un long deuxième mot interrompra votre programme.
Gabe
3
Je me demande pourquoi cela recueille encore des votes. La solution est incorrecte (dans le cas général) et les solutions Ruby bidirectionnelles plus courtes sont ici maintenant.
Joey
1
Maintenant, corrigez-moi si je me trompe, mais au lieu d'utiliser "downcase", pourquoi n'utilisez-vous pas l'indicateur insensible à la casse REGEXP, qui économise 6-7 octets, n'est-ce pas?
st0le
19

Python 2.x, approche latitudinaire = 227183 caractères

import sys,re
t=re.split('\W+',sys.stdin.read().lower())
r=sorted((-t.count(w),w)for w in set(t)if w not in'andithetoforinis')[:22]
for l,w in r:print(78-len(r[0][1]))*l/r[0][0]*'=',w

Permettant la liberté dans l'implémentation, j'ai construit une concaténation de chaînes qui contient tous les mots demandés pour l'exclusion ( the, and, of, to, a, i, it, in, or, is) - plus elle exclut également les deux infâmes "mots" set tde l'exemple - et j'ai ajouté gratuitement l'exclusion pour an, for, he. J'ai essayé toutes les concaténations de ces mots contre le corpus des mots d'Alice, de la Bible du roi Jacques et du fichier Jargon pour voir s'il y a des mots qui seront mal exclus par la chaîne. Et c'est ainsi que j'ai terminé avec deux chaînes d'exclusion: itheandtoforiniset andithetoforinis.

PS. emprunté à d'autres solutions pour raccourcir le code.

=========================================================================== she 
================================================================= you
============================================================== said
====================================================== alice
================================================ was
============================================ that
===================================== as
================================= her
============================== at
============================== with
=========================== on
=========================== all
======================== this
======================== had
======================= but
====================== be
====================== not
===================== they
==================== so
=================== very
=================== what
================= little

Rant

Concernant les mots à ignorer, on pourrait penser que ceux-ci seraient tirés de la liste des mots les plus utilisés en anglais. Cette liste dépend du corpus de texte utilisé. Selon l'une des listes les plus populaires ( http://en.wikipedia.org/wiki/Most_common_words_in_English , http://www.english-for-students.com/Frequent-Used-Words.html , http: // www. sporcle.com/games/common_english_words.php ), les 10 principaux mots sont:the be(am/are/is/was/were) to of and a in that have I

Les 10 premiers mots du texte d'Alice au pays des merveilles sont the and to a of it she i you said
Les 10 premiers mots du fichier Jargon (v4.4.7) sontthe a of to and in is that or for

La question est donc de savoir pourquoi a orété inclus dans la liste des ignorés du problème, où sa popularité est ~ 30e alors que le mot that(8e le plus utilisé) ne l'est pas. etc, etc. Par conséquent, je crois que la liste des ignorés devrait être fournie dynamiquement (ou pourrait être omise).

Une autre idée serait simplement de sauter les 10 premiers mots du résultat - ce qui raccourcirait en fait la solution (élémentaire - n'afficher que les 11e à 32e entrées).


Python 2.x, approche pointilleuse = 277243 caractères

Le graphique dessiné dans le code ci-dessus est simplifié (en utilisant un seul caractère pour les barres). Si l'on veut reproduire exactement le graphique à partir de la description du problème (ce qui n'était pas obligatoire), ce code le fera:

import sys,re
t=re.split('\W+',sys.stdin.read().lower())
r=sorted((-t.count(w),w)for w in set(t)-set(sys.argv))[:22]
h=min(9*l/(77-len(w))for l,w in r)
print'',9*r[0][0]/h*'_'
for l,w in r:print'|'+9*l/h*'_'+'|',w

Je pose un problème avec le choix quelque peu aléatoire des 10 mots à exclure the, and, of, to, a, i, it, in, or, isafin qu'ils soient passés en tant que paramètres de ligne de commande, comme ceci:
python WordFrequencyChart.py the and of to a i it in or is <"Alice's Adventures in Wonderland.txt"

C'est 213 caractères + 30 si l'on tient compte de la liste des ignorés "d'origine" passée sur la ligne de commande = 243

PS. Le deuxième code fait également un «ajustement» pour les longueurs de tous les premiers mots, de sorte qu'aucun d'entre eux ne débordera en cas de dégénération.

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|_____________________________________________________| said
|______________________________________________| alice
|_________________________________________| was
|______________________________________| that
|_______________________________| as
|____________________________| her
|__________________________| at
|__________________________| with
|_________________________| s
|_________________________| t
|_______________________| on
|_______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|___________________| not
|_________________| they
|_________________| so
Nas Banov
la source
Belle solution jusqu'à présent bien que le mot ignore list ne soit pas (encore) implémenté et que les barres soient un peu rudimentaires pour le moment.
ChristopheD
@ChristopheD: il était là, mais il n'y avait pas de "guide de l'utilisateur". Vient d'ajouter du texte de groupe
Nas Banov
En ce qui concerne votre liste de langues et de solutions: veuillez rechercher des solutions qui utilisent le fractionnement \Wou l'utilisation \bdans une expression régulière, car celles-ci ne sont probablement pas conformes aux spécifications, ce qui signifie qu'elles ne seront pas divisées en chiffres ou _qu'elles pourraient également ne pas supprimer les mots vides des chaînes. comme the_foo_or123bar. Ils peuvent ne pas apparaître dans le texte du test, mais la spécification est assez claire dans ce cas.
Joey du
Un travail incroyable Non, j'ai passé un après-midi à essayer d'optimiser cela et je n'ai trouvé qu'une seule amélioration. Vous pouvez le réduire à 239 caractères en supprimant le sys.argvhack et en utilisant:re.findall(r'\b(?!(?:the|and|.|of|to|i[tns]|or)\b)\w+',sys.stdin.read().lower())
intgr
12

Haskell - 366 351 344 337 333 caractères

(Un saut de ligne mainajouté pour plus de lisibilité, et aucun saut de ligne nécessaire à la fin de la dernière ligne.)

import Data.List
import Data.Char
l=length
t=filter
m=map
f c|isAlpha c=toLower c|0<1=' '
h w=(-l w,head w)
x!(q,w)='|':replicate(minimum$m(q?)x)'_'++"| "++w
q?(g,w)=q*(77-l w)`div`g
b x=m(x!)x
a(l:r)=(' ':t(=='_')l):l:r
main=interact$unlines.a.b.take 22.sort.m h.group.sort
  .t(`notElem`words"the and of to a i it in or is").words.m f

Comment cela fonctionne est mieux vu en lisant l'argument à l' interactenvers:

  • map f l'alphabet en minuscules, remplace tout le reste par des espaces.
  • words produit une liste de mots, en supprimant l'espace blanc de séparation.
  • filter (notElem words "the and of to a i it in or is")rejette toutes les entrées contenant des mots interdits.
  • group . sort trie les mots et regroupe les mots identiques en listes.
  • map hmappe chaque liste de mots identiques à un tuple du formulaire (-frequency, word).
  • take 22 . sort trie les tuples par fréquence décroissante (la première entrée de tuples) et ne conserve que les 22 premiers tuples.
  • b mappe les tuples en barres (voir ci-dessous).
  • a ajoute la première ligne de traits de soulignement pour compléter la barre supérieure.
  • unlines joint toutes ces lignes avec des nouvelles lignes.

Le plus délicat est d'obtenir la bonne longueur de barre. J'ai supposé que seuls les traits de soulignement comptaient dans la longueur de la barre, ce ||serait donc une barre de longueur nulle. La fonction bmappe c xsur x, où se xtrouve la liste des histogrammes. La liste entière est transmise à c, afin que chaque appel de cpuisse calculer le facteur d'échelle pour lui-même en appelant u. De cette façon, j'évite d'utiliser des mathématiques en virgule flottante ou des rationnels, dont les fonctions de conversion et les importations mangent beaucoup de caractères.

Notez l'astuce d'utilisation -frequency. Cela supprime le besoin de reversela sortcar le tri (croissant) -frequencyplace les mots avec la plus grande fréquence en premier. Plus tard, dans la fonction u, deux -frequencyvaleurs sont multipliées, ce qui annulera la négation.

Thomas
la source
Très beau travail (je voterais mais manquait de votes pour aujourd'hui avec toutes les bonnes réponses de ce fil).
ChristopheD
Cela me fait mal aux yeux d'une manière douloureuse même à penser à décrire, mais j'ai beaucoup appris sur Haskell en le reverse-engineering dans un code lisible. Bien joué, monsieur. :-)
Owen S.
C'est en fait encore assez idiomatique Haskell, mais pas vraiment efficace. Les noms courts donnent l'impression que c'est bien pire qu'il ne l'est en réalité.
Thomas le
@Thomas: Vous pouvez le répéter. :-)
Owen S.
1
Je ne peux pas déplacer le div, en fait! Essayez-le - la sortie est incorrecte. La raison en est que faire le divavant *perd de la précision.
MtnViewMark
11

JavaScript 1.8 (SpiderMonkey) - 354

x={};p='|';e=' ';z=[];c=77
while(l=readline())l.toLowerCase().replace(/\b(?!(the|and|of|to|a|i[tns]?|or)\b)\w+/g,function(y)x[y]?x[y].c++:z.push(x[y]={w:y,c:1}))
z=z.sort(function(a,b)b.c-a.c).slice(0,22)
for each(v in z){v.r=v.c/z[0].c
c=c>(l=(77-v.w.length)/v.r)?l:c}for(k in z){v=z[k]
s=Array(v.r*c|0).join('_')
if(!+k)print(e+s+e)
print(p+s+p+e+v.w)}

Malheureusement, la for([k,v]in z)version de Rhino ne semble pas vouloir fonctionner dans SpiderMonkey, et readFile()est un peu plus facile que de l'utiliser, readline()mais passer à la version 1.8 nous permet d'utiliser des fermetures de fonctions pour couper quelques lignes de plus ...

Ajout d'espaces blancs pour la lisibilité:

x={};p='|';e=' ';z=[];c=77
while(l=readline())
  l.toLowerCase().replace(/\b(?!(the|and|of|to|a|i[tns]?|or)\b)\w+/g,
   function(y) x[y] ? x[y].c++ : z.push( x[y] = {w: y, c: 1} )
  )
z=z.sort(function(a,b) b.c - a.c).slice(0,22)
for each(v in z){
  v.r=v.c/z[0].c
  c=c>(l=(77-v.w.length)/v.r)?l:c
}
for(k in z){
  v=z[k]
  s=Array(v.r*c|0).join('_')
  if(!+k)print(e+s+e)
  print(p+s+p+e+v.w)
}

Usage: js golf.js < input.txt

Production:

 _________________________________________________________________________ 
| _________________________________________________________________________ | elle
| _______________________________________________________________ | tu
| ____________________________________________________________ | m'a dit
| ____________________________________________________ | Alice
| ______________________________________________ | était
| ___________________________________________ | cette
| ___________________________________ | comme
| ________________________________ | sa
| _____________________________ | à
| _____________________________ | avec
| ____________________________ | s
| ____________________________ | t
| __________________________ | sur
| _________________________ | tout
| _______________________ | ce
| ______________________ | pour
| ______________________ | eu
| ______________________ | mais
| _____________________ | être
| _____________________ | ne pas
| ___________________ | ils
| ___________________ | alors

(version de base - ne gère pas correctement les largeurs de barres)

JavaScript (Rhino) - 405 395 387 377 368 343 304 caractères

Je pense que ma logique de tri est éteinte, mais .. je duno. Brainfart corrigé.

Minified (abuser \ninterprété comme ;parfois):

x={};p='|';e=' ';z=[]
readFile(arguments[0]).toLowerCase().replace(/\b(?!(the|and|of|to|a|i[tns]?|or)\b)\w+/g,function(y){x[y]?x[y].c++:z.push(x[y]={w:y,c:1})})
z=z.sort(function(a,b){return b.c-a.c}).slice(0,22)
for([k,v]in z){s=Array((v.c/z[0].c)*70|0).join('_')
if(!+k)print(e+s+e)
print(p+s+p+e+v.w)}
Mat
la source
Ah, monsieur. Je crois que c'est votre gant. Faites parler votre deuxième au mien.
dmckee --- ex-moderator chaton
2
BTW - J'aime le i[tns]?peu. Très sournois.
dmckee --- ex-moderator chaton
@dmckee - bien joué, je ne pense pas que je peux battre votre 336, profitez de votre vote positif bien mérité :)
Matt
Vous pouvez certainement battre 336 ... Il y a une coupe de 23 caractères disponible - .replace(/[^\w ]/g, e).split(/\s+/).map(peut être remplacée par .replace(/\w+/g,et utiliser la même fonction que vous avez .mapfait ... Je ne sais pas non plus si Rhino prend en charge à la function(a,b)b.c-a.cplace de votre fonction de tri (spidermonkey le fait), mais ce sera rasage {return }... b.c-a.cest un meilleur tri que a.c<b.cbtw ... Modification d'une version de Spidermonkey en bas avec ces changements
gnarf
J'ai déplacé ma version SpiderMonkey vers le haut car elle est conforme à la contrainte de largeur de la barre ... J'ai également réussi à couper quelques caractères supplémentaires dans votre version originale en utilisant une expression rationnelle de recherche négative pour refuser les mots permettant un seul remplacement (), et a joué au golf quelques si avec un ?:excellent point de départ pour travailler!
gnarf
11

Version PHP CLI (450 caractères)

Cette solution prend en compte la dernière exigence que la plupart des puristes ont choisi d'ignorer. Cela a coûté 170 caractères!

Usage: php.exe <this.php> <file.txt>

Minifié:

<?php $a=array_count_values(array_filter(preg_split('/[^a-z]/',strtolower(file_get_contents($argv[1])),-1,1),function($x){return !preg_match("/^(.|the|and|of|to|it|in|or|is)$/",$x);}));arsort($a);$a=array_slice($a,0,22);function R($a,$F,$B){$r=array();foreach($a as$x=>$f){$l=strlen($x);$r[$x]=$b=$f*$B/$F;if($l+$b>76)return R($a,$f,76-$l);}return$r;}$c=R($a,max($a),76-strlen(key($a)));foreach($a as$x=>$f)echo '|',str_repeat('-',$c[$x]),"| $x\n";?>

Lisible par l'homme:

<?php

// Read:
$s = strtolower(file_get_contents($argv[1]));

// Split:
$a = preg_split('/[^a-z]/', $s, -1, PREG_SPLIT_NO_EMPTY);

// Remove unwanted words:
$a = array_filter($a, function($x){
       return !preg_match("/^(.|the|and|of|to|it|in|or|is)$/",$x);
     });

// Count:
$a = array_count_values($a);

// Sort:
arsort($a);

// Pick top 22:
$a=array_slice($a,0,22);


// Recursive function to adjust bar widths
// according to the last requirement:
function R($a,$F,$B){
    $r = array();
    foreach($a as $x=>$f){
        $l = strlen($x);
        $r[$x] = $b = $f * $B / $F;
        if ( $l + $b > 76 )
            return R($a,$f,76-$l);
    }
    return $r;
}

// Apply the function:
$c = R($a,max($a),76-strlen(key($a)));


// Output:
foreach ($a as $x => $f)
    echo '|',str_repeat('-',$c[$x]),"| $x\n";

?>

Production:

|-------------------------------------------------------------------------| she
|---------------------------------------------------------------| you
|------------------------------------------------------------| said
|-----------------------------------------------------| alice
|-----------------------------------------------| was
|-------------------------------------------| that
|------------------------------------| as
|--------------------------------| her
|-----------------------------| at
|-----------------------------| with
|--------------------------| on
|--------------------------| all
|-----------------------| this
|-----------------------| for
|-----------------------| had
|-----------------------| but
|----------------------| be
|---------------------| not
|--------------------| they
|--------------------| so
|-------------------| very
|------------------| what

Lorsqu'il y a un mot long, les barres sont correctement ajustées:

|--------------------------------------------------------| she
|---------------------------------------------------| thisisareallylongwordhere
|-------------------------------------------------| you
|-----------------------------------------------| said
|-----------------------------------------| alice
|------------------------------------| was
|---------------------------------| that
|---------------------------| as
|-------------------------| her
|-----------------------| with
|-----------------------| at
|--------------------| on
|--------------------| all
|------------------| this
|------------------| for
|------------------| had
|-----------------| but
|-----------------| be
|----------------| not
|---------------| they
|---------------| so
|--------------| very
user382874
la source
11

Python 3.1 - 245 229 caractères

Je suppose qu'en utilisant Counter est une sorte de triche :) Je viens de lire à ce sujet il y a environ une semaine, donc c'était l'occasion parfaite de voir comment cela fonctionne.

import re,collections
o=collections.Counter([w for w in re.findall("[a-z]+",open("!").read().lower())if w not in"a and i in is it of or the to".split()]).most_common(22)
print('\n'.join('|'+76*v//o[0][1]*'_'+'| '+k for k,v in o))

Imprime:

|____________________________________________________________________________| she
|__________________________________________________________________| you
|_______________________________________________________________| said
|_______________________________________________________| alice
|_________________________________________________| was
|_____________________________________________| that
|_____________________________________| as
|__________________________________| her
|_______________________________| with
|_______________________________| at
|______________________________| s
|_____________________________| t
|____________________________| on
|___________________________| all
|________________________| this
|________________________| for
|________________________| had
|________________________| but
|______________________| be
|______________________| not
|_____________________| they
|____________________| so

Une partie du code a été "empruntée" à la solution d'AKX.

sdolan
la source
La première ligne est manquante. Et la longueur de la barre n'est pas correcte.
Joey
dans votre code semble que open('!')lit à partir de stdin - quelle version / OS est-ce sur? ou devez-vous nommer le fichier «!»?
Nas Banov
Nommez le fichier "!" :) Désolé, ce n'était pas clair, et j'aurais dû le mentionner.
Sam Dolan
11

perl, 205 191 189 205 caractères / caractères (entièrement mis en œuvre)

Certaines parties ont été inspirées par les précédentes soumissions perl / ruby, quelques idées similaires ont été élaborées indépendamment, les autres sont originales. La version plus courte intègre également certaines choses que j'ai vues / apprises d'autres soumissions.

Original:

$k{$_}++for grep{$_!~/^(the|and|of|to|a|i|it|in|or|is)$/}map{lc=~/[a-z]+/g}<>;@t=sort{$k{$b}<=>$k{$a}}keys%k;$l=76-length$t[0];printf" %s
",'_'x$l;printf"|%s| $_
",'_'x int$k{$_}/$k{$t[0]}*$l for@t[0..21];

Dernière version jusqu'à 191 caractères:

/^(the|and|of|to|.|i[tns]|or)$/||$k{$_}++for map{lc=~/[a-z]+/g}<>;@e=sort{$k{$b}<=>$k{$a}}keys%k;$n=" %s
";$r=(76-y///c)/$k{$_=$e[0]};map{printf$n,'_'x($k{$_}*$r),$_;$n="|%s| %s
"}@e[0,0..21]

Dernière version jusqu'à 189 caractères:

/^(the|and|of|to|.|i[tns]|or)$/||$k{$_}++for map{lc=~/[a-z]+/g}<>;@_=sort{$k{$b}<=>$k{$a}}keys%k;$n=" %s
";$r=(76-m//)/$k{$_=$_[0]};map{printf$n,'_'x($k{$_}*$r),$_;$n="|%s| %s
"}@_[0,0..21]

Cette version (205 caractères) tient compte des lignes avec des mots plus longs que ce qui serait trouvé plus tard.

/^(the|and|of|to|.|i[tns]|or)$/||$k{$_}++for map{lc=~/[a-z]+/g}<>;($r)=sort{$a<=>$b}map{(76-y///c)/$k{$_}}@e=sort{$k{$b}<=>$k{$a}}keys%k;$n=" %s
";map{printf$n,'_'x($k{$_}*$r),$_;$n="|%s| %s
";}@e[0,0..21]
pdehaan
la source
10

Perl: 203 202 201 198 195 208 203/231 caractères

$/=\0;/^(the|and|of|to|.|i[tns]|or)$/i||$x{lc$_}++for<>=~/[a-z]+/gi;map{$z=$x{$_};$y||{$y=(76-y///c)/$z}&&warn" "."_"x($z*$y)."\n";printf"|%.78s\n","_"x($z*$y)."| $_"}(sort{$x{$b}<=>$x{$a}}keys%x)[0..21]

Autre implémentation complète incluant le comportement indiqué (global bar-squishing) pour le cas pathologique dans lequel le mot secondaire est à la fois populaire et assez long pour se combiner à plus de 80 caractères ( cette implémentation est de 231 caractères ):

$/=\0;/^(the|and|of|to|.|i[tns]|or)$/i||$x{lc$_}++for<>=~/[a-z]+/gi;@e=(sort{$x{$b}<=>$x{$a}}keys%x)[0..21];for(@e){$p=(76-y///c)/$x{$_};($y&&$p>$y)||($y=$p)}warn" "."_"x($x{$e[0]}*$y)."\n";for(@e){warn"|"."_"x($x{$_}*$y)."| $_\n"}

La spécification n'indiquait nulle part que cela devait aller à STDOUT, j'ai donc utilisé warn () de perl au lieu de print - quatre caractères enregistrés ici. Carte utilisée au lieu de foreach, mais j'ai l'impression qu'il pourrait encore y avoir plus d'économies dans le fractionnement (join ()). Pourtant, je l'ai ramené à 203 - pourrait dormir dessus. Au moins Perl est maintenant sous le "shell, grep, tr, grep, sort, uniq, sort, head, perl" char count pour l'instant;)

PS: Reddit dit "Salut";)

Mise à jour: join () supprimée en faveur de l'affectation et de la jointure de conversion scalaire implicite. Jusqu'à 202. Veuillez également noter que j'ai profité de la règle facultative «ignorer les mots d'une lettre» pour supprimer 2 caractères, alors gardez à l'esprit que le nombre de fréquences reflètera cela.

Mise à jour 2: affectation permutée et jointure implicite pour tuer $ / pour obtenir le fichier en une seule prise en utilisant <> en premier lieu. Même taille, mais plus méchant. Remplacé if (! $ Y) {} contre $ y || {} &&, sauvé 1 autre char => 201.

Mise à jour 3: Prise de contrôle précoce des minuscules (lc <>) en déplaçant lc hors du bloc de carte - Échange les deux expressions régulières pour ne plus utiliser l'option / i, car elle n'est plus nécessaire. Construction conditionnelle explicite x? Y: z permutée pour perlgolf traditionnel || construction conditionnelle implicite - /^...$/i?1:$x{$ } ++ pour /^...$/||$x{$ } ++ Trois caractères enregistrés! => 198, a franchi la barrière des 200. Pourrait dormir bientôt ... peut-être.

Mise à jour 4: La privation de sommeil m'a rendu fou. Bien. Plus fou. Figurant que cela n'a qu'à analyser les fichiers texte heureux normaux, je l'ai fait abandonner s'il atteint un null. Sauvé deux caractères. Remplacement de "longueur" par le 1-caractère plus court (et beaucoup plus golfique) y /// c - vous m'entendez, GolfScript ?? Je viens pour toi!!! sanglot

Mise à jour 5: Sleep Dep m'a fait oublier la limite de 22 rangées et la limite de ligne suivante. Sauvegardez jusqu'à 208 avec ceux traités. Pas trop mal, 13 personnages à gérer ce n'est pas la fin du monde. J'ai joué avec l'évaluation en ligne de regex de perl, mais j'ai du mal à le faire fonctionner et enregistrer les caractères ... lol. Mise à jour de l'exemple pour correspondre à la sortie actuelle.

Mise à jour 6: Suppression des accolades inutiles protégeant (...) pour, puisque le bonbon syntaxique ++ permet de le pousser contre le pour heureusement. Merci à la contribution de Chas. Owens (rappelant mon cerveau fatigué), a obtenu la solution de classe de personnage i [tns] là-dedans. Revenons à 203.

Mise à jour 7: Ajout d'un deuxième travail, mise en œuvre complète des spécifications (y compris le comportement d'écrasement de la barre complet pour les mots longs secondaires, au lieu de la troncature que la plupart des gens font, basée sur la spécification d'origine sans le cas d'exemple pathologique)

Exemples:

 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|___________________________________________| that
|____________________________________| as
|________________________________| her
|_____________________________| with
|_____________________________| at
|__________________________| on
|__________________________| all
|_______________________| this
|_______________________| for
|_______________________| had
|_______________________| but
|______________________| be
|_____________________| not
|____________________| they
|____________________| so
|___________________| very
|__________________| what

Mise en œuvre alternative dans l'exemple de cas pathologique:

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| with
|_________________________| at
|_______________________| on
|______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| so
|________________| very
|________________| what
Syntaera
la source
Vous pouvez raccourcir l'expression régulière pour les mots vides is|in|it|ien vous réduisant à i[snt]?- et il n'y a plus de différence avec la règle facultative. (Hm, je n'aurais jamais pensé à dire à un gars de Perl comment faire Regex: D) - seul problème maintenant: je dois regarder comment je peux raser trois octets de ma propre solution pour être à nouveau meilleur que Perl: - |
Joey
Ok, ne tenez pas compte d'une partie de ce que j'ai dit plus tôt. Ignorer les mots d'une lettre est en effet un octet plus court que de ne pas le faire.
Joey
Chaque octet compte;) J'ai envisagé de faire le truc de nouvelle ligne, mais j'ai pensé que c'était en fait le même nombre d'octets, même s'il y avait moins de caractères imprimables. Je travaille toujours à voir si je peux le réduire encore plus :)
Syntaera
Eh bien, la normalisation des cas m'a renvoyé à 209. Je ne vois pas ce que je pourrais couper d'autre. Bien que PowerShell puisse être plus court que Perl. ;-)
Joey
Je ne vois pas où vous limitez la sortie aux 22 premiers mots, ni où vous vous assurez qu'un long deuxième mot ne s'enroule pas.
Gabe
9

F #, 452 caractères

Strightforward: obtenez une séquence ade paires de nombre de mots, trouvez le meilleur multiplicateur de nombre de mots par colonne k, puis imprimez les résultats.

let a=
 stdin.ReadToEnd().Split(" .?!,\":;'\r\n".ToCharArray(),enum 1)
 |>Seq.map(fun s->s.ToLower())|>Seq.countBy id
 |>Seq.filter(fun(w,n)->not(set["the";"and";"of";"to";"a";"i";"it";"in";"or";"is"].Contains w))
 |>Seq.sortBy(fun(w,n)-> -n)|>Seq.take 22
let k=a|>Seq.map(fun(w,n)->float(78-w.Length)/float n)|>Seq.min
let u n=String.replicate(int(float(n)*k)-2)"_"
printfn" %s "(u(snd(Seq.nth 0 a)))
for(w,n)in a do printfn"|%s| %s "(u n)w

Exemple (j'ai des nombres de fréquences différents de vous, je ne sais pas pourquoi):

% app.exe < Alice.txt

 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|___________________________________________| that
|___________________________________| as
|________________________________| her
|_____________________________| with
|_____________________________| at
|____________________________| t
|____________________________| s
|__________________________| on
|_________________________| all
|_______________________| this
|______________________| had
|______________________| for
|_____________________| but
|_____________________| be
|____________________| not
|___________________| they
|__________________| so
Brian
la source
il s'avère que ma propre solution était en effet un peu décalée (en raison d'un peu de spécification différente), les solutions correspondent maintenant ;-)
ChristopheD
+1 pour la seule implémentation correcte de la mise à l'échelle des barres à ce jour
Rotsor
2
(@Rotsor: Ironique, étant donné que la mienne est la solution la plus ancienne.)
Brian
Je parie que vous pourriez le raccourcir un peu en fusionnant les étapes de fractionnement, de carte et de filtre. Je m'attendrais également à ce que vous n'ayez pas besoin d'autant de floats.
Gabe
Les fonctions d'imbrication ne sont-elles généralement pas plus courtes que l'utilisation de l'opérateur de pipeline |>?
Joey
8

Python 2.6, 347 caractères

import re
W,x={},"a and i in is it of or the to".split()
[W.__setitem__(w,W.get(w,0)-1)for w in re.findall("[a-z]+",file("11.txt").read().lower())if w not in x]
W=sorted(W.items(),key=lambda p:p[1])[:22]
bm=(76.-len(W[0][0]))/W[0][1]
U=lambda n:"_"*int(n*bm)
print "".join(("%s\n|%s| %s "%((""if i else" "+U(n)),U(n),w))for i,(w,n)in enumerate(W))

Production:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
AKX
la source
1
Vous pouvez perdre la ligne bm=(76.-len(W[0][0]))/W[0][1]puisque vous n'utilisez bm qu'une seule fois (faites la ligne suivante U=lambda n:"_"*int(n*(76.-len(W[0][0]))/W[0][1]), rase 5 caractères. Aussi: pourquoi utiliseriez-vous un nom de variable à 2 caractères dans le code de golf? ;-)
ChristopheD
Sur la dernière ligne, l'espace après l'impression n'est pas nécessaire, rase un caractère
ChristopheD
1
Ne considère pas le cas où le deuxième mot le plus fréquent est très long, non?
Joey le
@ChristopheD: Parce que je regardais ce code depuis un peu trop longtemps. : P Bonne prise. @Johannes: Cela pourrait aussi être corrigé, oui. Je ne suis pas sûr que toutes les autres implémentations l'ont fait quand j'ai écrit ceci non plus.
AKX
7

* sh (+ curl), solution partielle

Ceci est incomplet, mais pour le plaisir, voici la fréquence des mots comptant la moitié du problème dans 192 octets:

curl -s http://www.gutenberg.org/files/11/11.txt|sed -e 's@[^a-z]@\n@gi'|tr '[:upper:]' '[:lower:]'|egrep -v '(^[^a-z]*$|\b(the|and|of|to|a|i|it|in|or|is)\b)' |sort|uniq -c|sort -n|tail -n 22
Frank Farmer
la source
7

Gawk - 336 (à l'origine 507) personnages

(après avoir corrigé le formatage de sortie; réparer le problème des contractions; peaufiner; peaufiner à nouveau; supprimer une étape de tri totalement inutile; peaufiner encore une fois; et encore (oups celui-ci a cassé le formatage); peaufiner un peu plus; relever le défi de Matt je peaufine désespérément tellement plus; trouvé un autre endroit pour en sauvegarder quelques-uns, mais en a rendu deux pour corriger le bogue de longueur de la barre)

Heh heh! Je suis momentanément en avance sur le défi du compteur de solutions [JavaScript de Matt] [1] ! ;) et [le python d'AKX] [2].

Le problème semble appeler un langage qui implémente des tableaux associatifs natifs, alors bien sûr, j'en ai choisi un avec un ensemble horriblement déficient d'opérateurs. En particulier, vous ne pouvez pas contrôler l'ordre dans lequel awk propose les éléments d'une carte de hachage, donc je scanne à plusieurs reprises toute la carte pour trouver l'élément actuellement le plus nombreux, l'imprimer et le supprimer du tableau.

Tout cela est terriblement inefficace, avec toutes les golfifcations que j'ai faites, cela est devenu assez horrible aussi.

Minifié:

{gsub("[^a-zA-Z]"," ");for(;NF;NF--)a[tolower($NF)]++}
END{split("the and of to a i it in or is",b," ");
for(w in b)delete a[b[w]];d=1;for(w in a){e=a[w]/(78-length(w));if(e>d)d=e}
for(i=22;i;--i){e=0;for(w in a)if(a[w]>e)e=a[x=w];l=a[x]/d-2;
t=sprintf(sprintf("%%%dc",l)," ");gsub(" ","_",t);if(i==22)print" "t;
print"|"t"| "x;delete a[x]}}

les sauts de ligne pour plus de clarté uniquement: ils ne sont pas nécessaires et ne doivent pas être comptés.


Production:

$ gawk -f wordfreq.awk.min < 11.txt 
 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|____________________________________________________________| said
|____________________________________________________| alice
|______________________________________________| was
|__________________________________________| that
|___________________________________| as
|_______________________________| her
|____________________________| with
|____________________________| at
|___________________________| s
|___________________________| t
|_________________________| on
|_________________________| all
|______________________| this
|______________________| for
|______________________| had
|_____________________| but
|____________________| be
|____________________| not
|___________________| they
|__________________| so
$ sed 's/you/superlongstring/gI' 11.txt | gawk -f wordfreq.awk.min
 ______________________________________________________________________
|______________________________________________________________________| she
|_____________________________________________________________| superlongstring
|__________________________________________________________| said
|__________________________________________________| alice
|____________________________________________| was
|_________________________________________| that
|_________________________________| as
|______________________________| her
|___________________________| with
|___________________________| at
|__________________________| s
|__________________________| t
|________________________| on
|________________________| all
|_____________________| this
|_____________________| for
|_____________________| had
|____________________| but
|___________________| be
|___________________| not
|__________________| they
|_________________| so

Lisible; 633 caractères (à l'origine 949):

{
    gsub("[^a-zA-Z]"," ");
    for(;NF;NF--)
    a[tolower($NF)]++
}
END{
    # remove "short" words
    split("the and of to a i it in or is",b," ");
    for (w in b) 
    delete a[b[w]];
    # Find the bar ratio
    d=1;
    for (w in a) {
    e=a[w]/(78-length(w));
    if (e>d)
        d=e
    }
    # Print the entries highest count first
    for (i=22; i; --i){               
    # find the highest count
    e=0;
    for (w in a) 
        if (a[w]>e)
        e=a[x=w];
        # Print the bar
    l=a[x]/d-2;
    # make a string of "_" the right length
    t=sprintf(sprintf("%%%dc",l)," ");
    gsub(" ","_",t);
    if (i==22) print" "t;
    print"|"t"| "x;
    delete a[x]
    }
}
dmckee
la source
Beau travail, bien vous avez inclus une version en retrait / commentée ;-)
ChristopheD
7

LISP commun, 670 caractères

Je suis un débutant LISP, et c'est une tentative d'utilisation d'une table de hachage pour le comptage (donc probablement pas la méthode la plus compacte).

(flet((r()(let((x(read-char t nil)))(and x(char-downcase x)))))(do((c(
make-hash-table :test 'equal))(w NIL)(x(r)(r))y)((not x)(maphash(lambda
(k v)(if(not(find k '("""the""and""of""to""a""i""it""in""or""is"):test
'equal))(push(cons k v)y)))c)(setf y(sort y #'> :key #'cdr))(setf y
(subseq y 0(min(length y)22)))(let((f(apply #'min(mapcar(lambda(x)(/(-
76.0(length(car x)))(cdr x)))y))))(flet((o(n)(dotimes(i(floor(* n f)))
(write-char #\_))))(write-char #\Space)(o(cdar y))(write-char #\Newline)
(dolist(x y)(write-char #\|)(o(cdr x))(format t "| ~a~%"(car x))))))
(cond((char<= #\a x #\z)(push x w))(t(incf(gethash(concatenate 'string(
reverse w))c 0))(setf w nil)))))

peut être exécuté par exemple avec cat alice.txt | clisp -C golf.lisp.

Sous une forme lisible est

(flet ((r () (let ((x (read-char t nil)))
               (and x (char-downcase x)))))
  (do ((c (make-hash-table :test 'equal))  ; the word count map
       w y                                 ; current word and final word list
       (x (r) (r)))  ; iteration over all chars
       ((not x)

        ; make a list with (word . count) pairs removing stopwords
        (maphash (lambda (k v)
                   (if (not (find k '("" "the" "and" "of" "to"
                                      "a" "i" "it" "in" "or" "is")
                                  :test 'equal))
                       (push (cons k v) y)))
                 c)

        ; sort and truncate the list
        (setf y (sort y #'> :key #'cdr))
        (setf y (subseq y 0 (min (length y) 22)))

        ; find the scaling factor
        (let ((f (apply #'min
                        (mapcar (lambda (x) (/ (- 76.0 (length (car x)))
                                               (cdr x)))
                                y))))
          ; output
          (flet ((outx (n) (dotimes (i (floor (* n f))) (write-char #\_))))
             (write-char #\Space)
             (outx (cdar y))
             (write-char #\Newline)
             (dolist (x y)
               (write-char #\|)
               (outx (cdr x))
               (format t "| ~a~%" (car x))))))

       ; add alphabetic to current word, and bump word counter
       ; on non-alphabetic
       (cond
        ((char<= #\a x #\z)
         (push x w))
        (t
         (incf (gethash (concatenate 'string (reverse w)) c 0))
         (setf w nil)))))
6502
la source
avez-vous essayé d'installer une macro de lecteur personnalisée pour réduire une certaine taille d'entrée?
Aaron
@Aaron en fait, ce n'était pas trivial pour moi, même si cela fonctionnait ... :-) pour la partie golfique, je viens d'utiliser des variables à une lettre et c'est tout. Quoi qu'il en soit, outre la verbosité quelque peu élevée qui est inhérente à CL pour cette échelle de problèmes ("concatenate 'string", "setf" ou "gethash" sont des tueurs ... en python ils sont "+", "=", "[]" ) encore, je ressentais cela bien pire que ce à quoi je m'attendais, même à un niveau logique. Dans un sens, j'ai le sentiment que le lisp est correct, mais le lisp commun est moyen et cela au-delà de la dénomination (le relire est un commentaire très injuste car mon expérience avec CL est proche de zéro).
6502
vrai. système rendrait le golf un peu plus facile, avec l'espace de noms unique. au lieu de string-append partout, vous pourriez (letrec ((a string-append) (b gethash)) ... (a "x" "yz") ...)
Aaron
6

C (828)

Il ressemble beaucoup à du code obscurci et utilise glib pour la chaîne, la liste et le hachage. Nombre de caractères avec wc -mdit 828 . Il ne considère pas les mots à caractère unique. Pour calculer la longueur maximale de la barre, il faut considérer le mot le plus long possible parmi tous, pas seulement le premier 22. Est-ce un écart par rapport à la spécification?

Il ne gère pas les échecs et ne libère pas la mémoire utilisée.

#include <glib.h>
#define S(X)g_string_##X
#define H(X)g_hash_table_##X
GHashTable*h;int m,w=0,z=0;y(const void*a,const void*b){int*A,*B;A=H(lookup)(h,a);B=H(lookup)(h,b);return*B-*A;}void p(void*d,void*u){int *v=H(lookup)(h,d);if(w<22){g_printf("|");*v=*v*(77-z)/m;while(--*v>=0)g_printf("=");g_printf("| %s\n",d);w++;}}main(c){int*v;GList*l;GString*s=S(new)(NULL);h=H(new)(g_str_hash,g_str_equal);char*n[]={"the","and","of","to","it","in","or","is"};while((c=getchar())!=-1){if(isalpha(c))S(append_c)(s,tolower(c));else{if(s->len>1){for(c=0;c<8;c++)if(!strcmp(s->str,n[c]))goto x;if((v=H(lookup)(h,s->str))!=NULL)++*v;else{z=MAX(z,s->len);v=g_malloc(sizeof(int));*v=1;H(insert)(h,g_strdup(s->str),v);}}x:S(truncate)(s,0);}}l=g_list_sort(H(get_keys)(h),y);m=*(int*)H(lookup)(h,g_list_first(l)->data);g_list_foreach(l,p,NULL);}
ShinTakezou
la source
Les retours à la ligne comptent comme des caractères, mais vous pouvez en supprimer des lignes qui ne sont pas des instructions de préprocesseur. Pour un golf, je ne considérerais pas le fait de ne pas libérer la mémoire comme une mauvaise pratique.
Stéphan Kochen le
ok ... mettre tout dans une ligne (attendez les macros preproc) et donné un vers sans libérer mem (et avec deux autres espaces supprimés ... un peu d'amélioration peut être faite sur le "masquage", par exemple *v=*v*(77-lw)/mdonnera 929. .. mais je pense que ça peut aller à moins que je trouve un moyen de le faire beaucoup plus court)
ShinTakezou
Je pense que vous pouvez déplacer au moins int cdans la maindéclaration et mainest implicitement int(tout comme les arguments non typées, autant que je sache): main(c){...}. Vous pourriez probablement aussi simplement écrire à la 0place de NULL.
Joey le
le faire ... bien sûr déclenchera un avertissement avec le -Wallou avec le -std=c99drapeau sur ... mais je suppose que c'est inutile pour un code-golf, non?
ShinTakezou
uff, désolé pour les modifications de courte durée, ... Je devrais passer Without freeing memory stuff, it reaches 866 (removed some other unuseful space)à autre chose pour ne pas laisser penser aux gens que la différence avec la version à mémoire libre réside dans cela: maintenant, la version sans mémoire libre a beaucoup de plus "d'améliorations".
ShinTakezou
6

Perl, 185 caractères

200 (légèrement cassé) 199 197 195 193 187 185 caractères. Les deux dernières nouvelles lignes sont importantes. Conforme à la spécification.

map$X{+lc}+=!/^(.|the|and|to|i[nst]|o[rf])$/i,/[a-z]+/gfor<>;
$n=$n>($:=$X{$_}/(76-y+++c))?$n:$:for@w=(sort{$X{$b}-$X{$a}}%X)[0..21];
die map{$U='_'x($X{$_}/$n);" $U
"x!$z++,"|$U| $_
"}@w

La première ligne charge le nombre de mots valides dans %X.

La deuxième ligne calcule le facteur de mise à l'échelle minimum pour que toutes les lignes de sortie soient <= 80 caractères.

La troisième ligne (contient deux caractères de nouvelle ligne) produit la sortie.

mob
la source
Cela ne supprimera pas les mots vides des chaînes telles que "foo_the_bar". La longueur de la ligne est également trop longue (relisez la spécification: "barre + espace + mot + espace <= 80 caractères")
Joey
5

Java - 886 865 756 744 742 744 752 742 714 680 caractères

  • Mises à jour avant le premier 742 : regex amélioré, suppression des types paramétrés superflus, suppression des espaces blancs superflus.

  • Mise à jour 742> 744 caractères : correction du hack de longueur fixe. Cela ne dépend que du premier mot, pas d'autres mots (encore). J'ai trouvé plusieurs endroits pour raccourcir le code ( \\sdans regex remplacé par et ArrayListremplacé par Vector). Je cherche maintenant un moyen court de supprimer la dépendance Commons IO et la lecture de stdin.

  • Mise à jour 744> 752 caractères : j'ai supprimé la dépendance commune. Il lit maintenant depuis stdin. Collez le texte dans stdin et appuyez sur Ctrl+Zpour obtenir le résultat.

  • Mise à jour 752> 742 caractères : J'ai supprimé publicet un espace, fait de nom de classe 1 caractère au lieu de 2 et il ignore maintenant les mots d'une lettre.

  • Mise à jour 742> 714 caractères : mise à jour selon les commentaires de Carl: suppression de l'affectation redondante (742> 730), remplacée m.containsKey(k)par m.get(k)!=null(730> 728), introduction de la sous-chaîne de la ligne (728> 714).

  • Mise à jour 714> 680 caractères : mise à jour selon les commentaires de Rotsor: amélioration du calcul de la taille de la barre pour supprimer les castes inutiles et amélioration split()pour supprimer les inutiles replaceAll().


import java.util.*;class F{public static void main(String[]a)throws Exception{StringBuffer b=new StringBuffer();for(int c;(c=System.in.read())>0;b.append((char)c));final Map<String,Integer>m=new HashMap();for(String w:b.toString().toLowerCase().split("(\\b(.|the|and|of|to|i[tns]|or)\\b|\\W)+"))m.put(w,m.get(w)!=null?m.get(w)+1:1);List<String>l=new Vector(m.keySet());Collections.sort(l,new Comparator(){public int compare(Object l,Object r){return m.get(r)-m.get(l);}});int c=76-l.get(0).length();String s=new String(new char[c]).replace('\0','_');System.out.println(" "+s);for(String w:l.subList(0,22))System.out.println("|"+s.substring(0,m.get(w)*c/m.get(l.get(0)))+"| "+w);}}

Version plus lisible:

import java.util.*;
class F{
 public static void main(String[]a)throws Exception{
  StringBuffer b=new StringBuffer();for(int c;(c=System.in.read())>0;b.append((char)c));
  final Map<String,Integer>m=new HashMap();for(String w:b.toString().toLowerCase().split("(\\b(.|the|and|of|to|i[tns]|or)\\b|\\W)+"))m.put(w,m.get(w)!=null?m.get(w)+1:1);
  List<String>l=new Vector(m.keySet());Collections.sort(l,new Comparator(){public int compare(Object l,Object r){return m.get(r)-m.get(l);}});
  int c=76-l.get(0).length();String s=new String(new char[c]).replace('\0','_');System.out.println(" "+s);
  for(String w:l.subList(0,22))System.out.println("|"+s.substring(0,m.get(w)*c/m.get(l.get(0)))+"| "+w);
 }
}

Production:

 _________________________________________________________________________
| _________________________________________________________________________ | elle
| _______________________________________________________________ | tu
| ____________________________________________________________ | m'a dit
| _____________________________________________________ | Alice
| _______________________________________________ | était
| ___________________________________________ | cette
| ____________________________________ | comme
| ________________________________ | sa
| _____________________________ | avec
| _____________________________ | à
| __________________________ | sur
| __________________________ | tout
| _______________________ | ce
| _______________________ | pour
| _______________________ | eu
| _______________________ | mais
| ______________________ | être
| _____________________ | ne pas
| ____________________ | ils
| ____________________ | alors
| ___________________ | très
| __________________ | quelle

C'est assez nul que Java n'ait pas String#join()et se ferme (encore).

Édité par Rotsor:

J'ai apporté plusieurs modifications à votre solution:

  • Liste remplacée par une chaîne []
  • Réutilisation de l'argument 'args' au lieu de déclarer mon propre tableau String. Également utilisé comme argument de .ToArray ()
  • Remplacement de StringBuffer par une chaîne (oui, oui, performances terribles)
  • Remplacement du tri Java par un tri par sélection avec arrêt précoce (seuls les 22 premiers éléments doivent être trouvés)
  • Agrégation d'une déclaration int en une seule instruction
  • Implémentation de l'algorithme de non-triche pour trouver la ligne de sortie la plus limitante. Je l'ai implémenté sans FP.
  • Correction du problème de plantage du programme lorsqu'il y avait moins de 22 mots distincts dans le texte
  • Implémentation d'un nouvel algorithme de lecture d'entrée, qui est rapide et seulement 9 caractères plus long que le lent.

Le code condensé contient 688 711 684 caractères:

import java.util.*;class F{public static void main(String[]l)throws Exception{Map<String,Integer>m=new HashMap();String w="";int i=0,k=0,j=8,x,y,g=22;for(;(j=System.in.read())>0;w+=(char)j);for(String W:w.toLowerCase().split("(\\b(.|the|and|of|to|i[tns]|or)\\b|\\W)+"))m.put(W,m.get(W)!=null?m.get(W)+1:1);l=m.keySet().toArray(l);x=l.length;if(x<g)g=x;for(;i<g;++i)for(j=i;++j<x;)if(m.get(l[i])<m.get(l[j])){w=l[i];l[i]=l[j];l[j]=w;}for(;k<g;k++){x=76-l[k].length();y=m.get(l[k]);if(k<1||y*i>x*j){i=x;j=y;}}String s=new String(new char[m.get(l[0])*i/j]).replace('\0','_');System.out.println(" "+s);for(k=0;k<g;k++){w=l[k];System.out.println("|"+s.substring(0,m.get(w)*i/j)+"| "+w);}}}

La version rapide ( 720 693 caractères)

import java.util.*;class F{public static void main(String[]l)throws Exception{Map<String,Integer>m=new HashMap();String w="";int i=0,k=0,j=8,x,y,g=22;for(;j>0;){j=System.in.read();if(j>90)j-=32;if(j>64&j<91)w+=(char)j;else{if(!w.matches("^(|.|THE|AND|OF|TO|I[TNS]|OR)$"))m.put(w,m.get(w)!=null?m.get(w)+1:1);w="";}}l=m.keySet().toArray(l);x=l.length;if(x<g)g=x;for(;i<g;++i)for(j=i;++j<x;)if(m.get(l[i])<m.get(l[j])){w=l[i];l[i]=l[j];l[j]=w;}for(;k<g;k++){x=76-l[k].length();y=m.get(l[k]);if(k<1||y*i>x*j){i=x;j=y;}}String s=new String(new char[m.get(l[0])*i/j]).replace('\0','_');System.out.println(" "+s);for(k=0;k<g;k++){w=l[k];System.out.println("|"+s.substring(0,m.get(w)*i/j)+"| "+w);}}}

Version plus lisible:

import java.util.*;class F{public static void main(String[]l)throws Exception{
    Map<String,Integer>m=new HashMap();String w="";
    int i=0,k=0,j=8,x,y,g=22;
    for(;j>0;){j=System.in.read();if(j>90)j-=32;if(j>64&j<91)w+=(char)j;else{
        if(!w.matches("^(|.|THE|AND|OF|TO|I[TNS]|OR)$"))m.put(w,m.get(w)!=null?m.get(w)+1:1);w="";
    }}
    l=m.keySet().toArray(l);x=l.length;if(x<g)g=x;
    for(;i<g;++i)for(j=i;++j<x;)if(m.get(l[i])<m.get(l[j])){w=l[i];l[i]=l[j];l[j]=w;}
    for(;k<g;k++){x=76-l[k].length();y=m.get(l[k]);if(k<1||y*i>x*j){i=x;j=y;}}
    String s=new String(new char[m.get(l[0])*i/j]).replace('\0','_');
    System.out.println(" "+s);
    for(k=0;k<g;k++){w=l[k];System.out.println("|"+s.substring(0,m.get(w)*i/j)+"| "+w);}}
}

La version sans améliorations de comportement est de 615 caractères:

import java.util.*;class F{public static void main(String[]l)throws Exception{Map<String,Integer>m=new HashMap();String w="";int i=0,k=0,j=8,g=22;for(;j>0;){j=System.in.read();if(j>90)j-=32;if(j>64&j<91)w+=(char)j;else{if(!w.matches("^(|.|THE|AND|OF|TO|I[TNS]|OR)$"))m.put(w,m.get(w)!=null?m.get(w)+1:1);w="";}}l=m.keySet().toArray(l);for(;i<g;++i)for(j=i;++j<l.length;)if(m.get(l[i])<m.get(l[j])){w=l[i];l[i]=l[j];l[j]=w;}i=76-l[0].length();String s=new String(new char[i]).replace('\0','_');System.out.println(" "+s);for(k=0;k<g;k++){w=l[k];System.out.println("|"+s.substring(0,m.get(w)*i/m.get(l[0]))+"| "+w);}}}
BalusC
la source
Ne pourriez-vous pas simplement utiliser le nom complet au IOUtilslieu de l'importer? Pour autant que je sache, vous ne l'utilisez qu'une seule fois de toute façon.
Joey
5
Vous avez en quelque sorte triché en supposant que la barre la plus longue contiendra exactement 75 caractères. Vous devez vous assurer qu'aucune barre + mot ne dépasse 80 caractères.
Gabe
Il vous manque un espace après le mot. ;)
st0le
Alors que je réduisais ma réponse , j'espérais avoir battu la soumission de BalusC. Il me reste encore 200 personnages à jouer, ugh! Je me demande combien de temps cela durerait sans l'hypothèse de Commons IO & 75 char.
Jonathon Faust
1
On dirait que vous pourriez raser certains caractères en créant bun String au lieu d'un StringBuffer. Cependant, je ne veux pas penser à ce que serait la performance (d'autant plus que vous ajoutez un personnage à la fois).
Michael Myers
4

Scala 2.8, 311 314 320 330 332 336 341 375 caractères

y compris l'ajustement des mots longs. Idées empruntées aux autres solutions.

Maintenant sous forme de script ( a.scala):

val t="\\w+\\b(?<!\\bthe|and|of|to|a|i[tns]?|or)".r.findAllIn(io.Source.fromFile(argv(0)).mkString.toLowerCase).toSeq.groupBy(w=>w).mapValues(_.size).toSeq.sortBy(-_._2)take 22
def b(p:Int)="_"*(p*(for((w,c)<-t)yield(76.0-w.size)/c).min).toInt
println(" "+b(t(0)._2))
for(p<-t)printf("|%s| %s \n",b(p._2),p._1)

Courir avec

scala -howtorun:script a.scala alice.txt

BTW, l'édition de 314 à 311 caractères ne supprime en fait qu'un seul caractère. Quelqu'un s'est trompé de comptage avant (Windows CR?).

mkneissl
la source
4

Clojure 282 strict

(let[[[_ m]:as s](->>(slurp *in*).toLowerCase(re-seq #"\w+\b(?<!\bthe|and|of|to|a|i[tns]?|or)")frequencies(sort-by val >)(take 22))[b](sort(map #(/(- 76(count(key %)))(val %))s))p #(do(print %1)(dotimes[_(* b %2)](print \_))(apply println %&))](p " " m)(doseq[[k v]s](p \| v \| k)))

Un peu plus lisiblement:

(let[[[_ m]:as s](->> (slurp *in*)
                   .toLowerCase
                   (re-seq #"\w+\b(?<!\bthe|and|of|to|a|i[tns]?|or)")
                   frequencies
                   (sort-by val >)
                   (take 22))
     [b] (sort (map #(/ (- 76 (count (key %)))(val %)) s))
     p #(do
          (print %1)
          (dotimes[_(* b %2)] (print \_))
          (apply println %&))]
  (p " " m)
  (doseq[[k v] s] (p \| v \| k)))
Alex Taggart
la source
4

Scala, 368 caractères

Tout d'abord, une version lisible en 592 caractères:

object Alice {
  def main(args:Array[String]) {
    val s = io.Source.fromFile(args(0))
    val words = s.getLines.flatMap("(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r.findAllIn(_)).map(_.toLowerCase)
    val freqs = words.foldLeft(Map[String, Int]())((countmap, word)  => countmap + (word -> (countmap.getOrElse(word, 0)+1)))
    val sortedFreqs = freqs.toList.sort((a, b)  => a._2 > b._2)
    val top22 = sortedFreqs.take(22)
    val highestWord = top22.head._1
    val highestCount = top22.head._2
    val widest = 76 - highestWord.length
    println(" " + "_" * widest)
    top22.foreach(t => {
      val width = Math.round((t._2 * 1.0 / highestCount) * widest).toInt
      println("|" + "_" * width + "| " + t._1)
    })
  }
}

La sortie de la console ressemble à ceci:

$ scalac alice.scala 
$ scala Alice aliceinwonderland.txt
 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|____________________________________________| that
|____________________________________| as
|_________________________________| her
|______________________________| at
|______________________________| with
|_____________________________| s
|_____________________________| t
|___________________________| on
|__________________________| all
|_______________________| had
|_______________________| but
|______________________| be
|______________________| not
|____________________| they
|____________________| so
|___________________| very
|___________________| what

Nous pouvons faire une minification agressive et la réduire à 415 caractères:

object A{def main(args:Array[String]){val l=io.Source.fromFile(args(0)).getLines.flatMap("(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r.findAllIn(_)).map(_.toLowerCase).foldLeft(Map[String, Int]())((c,w)=>c+(w->(c.getOrElse(w,0)+1))).toList.sort((a,b)=>a._2>b._2).take(22);println(" "+"_"*(76-l.head._1.length));l.foreach(t=>println("|"+"_"*Math.round((t._2*1.0/l.head._2)*(76-l.head._1.length)).toInt+"| "+t._1))}}

La session de console ressemble à ceci:

$ scalac a.scala 
$ scala A aliceinwonderland.txt
 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|____________________________________________| that
|____________________________________| as
|_________________________________| her
|______________________________| at
|______________________________| with
|_____________________________| s
|_____________________________| t
|___________________________| on
|__________________________| all
|_______________________| had
|_______________________| but
|______________________| be
|______________________| not
|____________________| they
|____________________| so
|___________________| very
|___________________| what

Je suis sûr qu'un expert Scala pourrait faire encore mieux.

Mise à jour: Dans les commentaires, Thomas a donné une version encore plus courte, à 368 caractères:

object A{def main(a:Array[String]){val t=(Map[String, Int]()/:(for(x<-io.Source.fromFile(a(0)).getLines;y<-"(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r findAllIn x) yield y.toLowerCase).toList)((c,x)=>c+(x->(c.getOrElse(x,0)+1))).toList.sortBy(_._2).reverse.take(22);val w=76-t.head._1.length;print(" "+"_"*w);t map (s=>"\n|"+"_"*(s._2*w/t.head._2)+"| "+s._1) foreach print}}

Lisiblement, à 375 caractères:

object Alice {
  def main(a:Array[String]) {
    val t = (Map[String, Int]() /: (
      for (
        x <- io.Source.fromFile(a(0)).getLines
        y <- "(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r.findAllIn(x)
      ) yield y.toLowerCase
    ).toList)((c, x) => c + (x -> (c.getOrElse(x, 0) + 1))).toList.sortBy(_._2).reverse.take(22)
    val w = 76 - t.head._1.length
    print (" "+"_"*w)
    t.map(s => "\n|" + "_" * (s._2 * w / t.head._2) + "| " + s._1).foreach(print)
  }
}
pr1001
la source
383 caractères:object A{def main(a:Array[String]){val t=(Map[String, Int]()/:(for(x<-io.Source.fromFile(a(0)).getLines;y<-"(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r findAllIn x) yield y.toLowerCase).toList)((c,x)=>c+(x->(c.getOrElse(x,0)+1))).toList.sortBy(_._2).reverse.take(22);val w=76-t.head._1.length;print(" "+"_"*w);t map (s=>"\n|"+"_"*(s._2*w/t.head._2)+"| "+s._1) foreach print}}
Thomas Jung
Bien sûr, le toujours pratique pour la compréhension! Agréable!
pr1001
3

Java - 896 caractères

931 caractères

1233 caractères rendus illisibles

1977 caractères "non compressés"


Mise à jour: j'ai considérablement réduit le nombre de personnages. Omet les mots à une seule lettre selon la spécification mise à jour.

J'envie tellement C # et LINQ.

import java.util.*;import java.io.*;import static java.util.regex.Pattern.*;class g{public static void main(String[] a)throws Exception{PrintStream o=System.out;Map<String,Integer> w=new HashMap();Scanner s=new Scanner(new File(a[0])).useDelimiter(compile("[^a-z]+|\\b(the|and|of|to|.|it|in|or|is)\\b",2));while(s.hasNext()){String z=s.next().trim().toLowerCase();if(z.equals(""))continue;w.put(z,(w.get(z)==null?0:w.get(z))+1);}List<Integer> v=new Vector(w.values());Collections.sort(v);List<String> q=new Vector();int i,m;i=m=v.size()-1;while(q.size()<22){for(String t:w.keySet())if(!q.contains(t)&&w.get(t).equals(v.get(i)))q.add(t);i--;}int r=80-q.get(0).length()-4;String l=String.format("%1$0"+r+"d",0).replace("0","_");o.println(" "+l);o.println("|"+l+"| "+q.get(0)+" ");for(i=m-1;i>m-22;i--){o.println("|"+l.substring(0,(int)Math.round(r*(v.get(i)*1.0)/v.get(m)))+"| "+q.get(m-i)+" ");}}}

"Lisible":

import java.util.*;
import java.io.*;
import static java.util.regex.Pattern.*;
class g
{
   public static void main(String[] a)throws Exception
      {
      PrintStream o = System.out;
      Map<String,Integer> w = new HashMap();
      Scanner s = new Scanner(new File(a[0]))
         .useDelimiter(compile("[^a-z]+|\\b(the|and|of|to|.|it|in|or|is)\\b",2));
      while(s.hasNext())
      {
         String z = s.next().trim().toLowerCase();
         if(z.equals(""))
            continue;
         w.put(z,(w.get(z) == null?0:w.get(z))+1);
      }
      List<Integer> v = new Vector(w.values());
      Collections.sort(v);
      List<String> q = new Vector();
      int i,m;
      i = m = v.size()-1;
      while(q.size()<22)
      {
         for(String t:w.keySet())
            if(!q.contains(t)&&w.get(t).equals(v.get(i)))
               q.add(t);
         i--;
      }
      int r = 80-q.get(0).length()-4;
      String l = String.format("%1$0"+r+"d",0).replace("0","_");
      o.println(" "+l);
      o.println("|"+l+"| "+q.get(0)+" ");
      for(i = m-1; i > m-22; i--)
      {
         o.println("|"+l.substring(0,(int)Math.round(r*(v.get(i)*1.0)/v.get(m)))+"| "+q.get(m-i)+" ");
      }
   }
}

Sortie d'Alice:

 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|____________________________________________| that
|____________________________________| as
|_________________________________| her
|______________________________| with
|______________________________| at
|___________________________| on
|__________________________| all
|________________________| this
|________________________| for
|_______________________| had
|_______________________| but
|______________________| be
|______________________| not
|____________________| they
|____________________| so
|___________________| very
|___________________| what

Sortie de Don Quichotte (également de Gutenberg):

 ________________________________________________________________________
|________________________________________________________________________| that
|________________________________________________________| he
|______________________________________________| for
|__________________________________________| his
|________________________________________| as
|__________________________________| with
|_________________________________| not
|_________________________________| was
|________________________________| him
|______________________________| be
|___________________________| don
|_________________________| my
|_________________________| this
|_________________________| all
|_________________________| they
|________________________| said
|_______________________| have
|_______________________| me
|______________________| on
|______________________| so
|_____________________| you
|_____________________| quixote
Jonathon
la source
8
Complètement carpe, n'y a-t-il vraiment aucun moyen de le raccourcir en Java? J'espère que vous serez payés par nombre de caractères et non par fonctionnalité :-)
Nas Banov