Construya un cuadro ASCII de las palabras más utilizadas en un texto dado [cerrado]

156

El reto:

Cree un cuadro ASCII de las palabras más utilizadas en un texto dado.

Las normas:

  • Solo acepta a-zy A-Z(caracteres alfabéticos) como parte de una palabra.
  • Ignorar la carcasa ( She== shepara nuestro propósito).
  • Ignora las siguientes palabras (bastante arbitrario, lo sé): the, and, of, to, a, i, it, in, or, is
  • Aclaración: considerando don't: esto se tomaría como 2 'palabras' diferentes en los rangos a-zy A-Z: ( dony t).

  • Opcionalmente (es demasiado tarde para cambiar formalmente las especificaciones ahora), puede optar por eliminar todas las 'palabras' de una sola letra (esto también podría acortar la lista de ignorados).

Analice un determinado text(lea un archivo especificado a través de argumentos de línea de comando o entorpecido; presuma us-ascii) y construya un a word frequency chartcon las siguientes características:

  • Muestre la tabla (también vea el ejemplo a continuación) para las 22 palabras más comunes (ordenadas por frecuencia descendente).
  • El bar width representa el número de ocurrencias (frecuencia) de la palabra (proporcionalmente). Agregue un espacio e imprima la palabra.
  • Asegúrese de que estas barras (más espacio-palabra-espacio) siempre encajan : bar+ [space]+ word+ [space]siempre deben tener <= 80caracteres (asegúrese de tener en cuenta las posibles longitudes de barra y palabra diferentes: por ejemplo: la segunda palabra más común podría ser mucho más larga que el primero aunque no difiere mucho en frecuencia). Maximice el ancho de la barra dentro de estas restricciones y escale las barras adecuadamente (de acuerdo con las frecuencias que representan).

Un ejemplo:

El texto para el ejemplo se puede encontrar aquí ( Alice's Adventures in Wonderland, por Lewis Carroll ).

Este texto específico produciría el siguiente cuadro:

 _________________________________________________________________________
| _________________________________________________________________________ | ella
| _______________________________________________________________ | tú
| ____________________________________________________________ | dijo
| ____________________________________________________ | Alicia
| ______________________________________________ | estaba
| __________________________________________ | ese
| ___________________________________ | como
| _______________________________ | su
| ____________________________ | con
| ____________________________ | a
| ___________________________ | s
| ___________________________ | t
| _________________________ | en
| _________________________ | todas
| ______________________ | esta
| ______________________ | para
| ______________________ | tenido
| _____________________ | pero
| ____________________ | ser
| ____________________ | no
| ___________________ | ellos
| __________________ | entonces


Para su información: estas son las frecuencias sobre las que se basa la tabla anterior:

[('ella', 553), ('usted', 481), ('dijo', 462), ('alicia', 403), ('era', 358), ('que
', 330), (' como ', 274), (' ella ', 248), (' con ', 227), (' en ', 227), (' s ', 219), (' t '
, 218), ('on', 204), ('all', 200), ('this', 181), ('for', 179), ('had', 178), ('
pero ', 175), (' be ', 167), (' not ', 166), (' they ', 155), (' so ', 152)]

Un segundo ejemplo (para verificar si implementó la especificación completa): reemplace cada aparición youen el archivo vinculado Alicia en el país de las maravillas con superlongstringstring:

 ________________________________________________________________
| ________________________________________________________________ | ella
| _______________________________________________________ | superlongstringstring
| _____________________________________________________ | dijo
| ______________________________________________ | Alicia
| ________________________________________ | estaba
| _____________________________________ | ese
| ______________________________ | como
| ___________________________ | su
| _________________________ | con
| _________________________ | a
| ________________________ | s
| ________________________ | t
| ______________________ | en
| _____________________ | todas
| ___________________ | esta
| ___________________ | para
| ___________________ | tenido
| __________________ | pero
| _________________ | ser
| _________________ | no
| ________________ | ellos
| ________________ | entonces

El ganador:

La solución más corta (por número de caracteres, por idioma). ¡Que te diviertas!


Editar : Tabla que resume los resultados hasta el momento (15/02/2012) (originalmente agregado por el usuario Nas Banov):

Lenguaje Relajado Estricto
========= ======= ======
GolfScript 130 143
Perl 185
Windows PowerShell 148 199
Mathematica 199
Ruby 185 205
Unix Toolchain 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
PHP 450
F # 452
TSQL 483 507

Los números representan la longitud de la solución más corta en un idioma específico. "Estricto" se refiere a una solución que implementa la especificación por completo (dibuja |____|barras, cierra la primera barra en la parte superior con una ____línea, explica la posibilidad de palabras largas con alta frecuencia, etc.). "Relajado" significa que se tomaron algunas libertades para acortar la solución.

Solo se incluyen soluciones de menos de 500 caracteres. La lista de idiomas está ordenada por la longitud de la solución 'estricta'. 'Unix Toolchain' se usa para significar varias soluciones que usan el tradicional * nix shell más una combinación de herramientas (como grep, tr, sort, uniq, head, perl, awk).

ChristopheD
fuente
44
Bueno, 'barra más larga' + palabra = 80 puede no caber dentro de 80 cols si la segunda palabra más común es una palabra mucho más larga. Estoy buscando la 'restricción máxima', supongo.
Brian
1
¿Normalizamos la carcasa? 'Ella' = 'ella'?
Brian
2
OMI haciendo que esto funcione, tanto en términos de tiempo de ejecución como de uso de memoria, parece un desafío más interesante que el recuento de caracteres.
Frank Farmer
81
Me alegra ver que mis palabras favoritas sy testán representadas.
indiv
8
@indiv, @Nas Banov: un tokenizador tonto y demasiado simple dice "no" como {didn, t} y "ella" como {ella, s} :)
hobbs

Respuestas:

123

LabVIEW 51 nodos, 5 estructuras, 10 diagramas

Enseñarle al elefante a bailar tap nunca es bonito. Voy a, ah, omitir el recuento de caracteres.

código de labVIEW

resultados

El programa fluye de izquierda a derecha:

código de labVIEW explicado

Joe Zoller
fuente
10
No vale la pena
44
LabVIEW está muy contento en su nicho de control y medición de hardware, pero es realmente horrible para la manipulación de cadenas.
Joe Z
19
La mejor respuesta de código de golf que he visto. ¡+1 por pensar fuera de la caja!
Blair Holloway
1
Tenemos que contar los elementos para nosotros ... cada cuadro y widget que tenías que arrastrar a la pantalla cuenta.
dmckee --- ex-gatito moderador
1
¿Sería posible agregar un enlace a una versión más grande de esos gráficos?
Svish
42

Ruby 1.9, 185 caracteres

(fuertemente basado en las otras soluciones de 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}]

En lugar de usar cualquier cambio de línea de comando como las otras soluciones, simplemente puede pasar el nombre del archivo como argumento. (es decir ruby1.9 wordfrequency.rb Alice.txt)

Como estoy usando literales de caracteres aquí, esta solución solo funciona en Ruby 1.9.

Editar: Se sustituyen los punto y coma por saltos de línea para "legibilidad". :PAGS

Edición 2: Shtééf señaló que olvidé el espacio final, lo arreglé.

Edición 3: se eliminó el espacio final nuevamente;)

Ventero
fuente
Falta el espacio final, después de cada palabra.
Stéphan Kochen
Aww disparar, ignorar eso. Parece que el golf se acaba de actualizar, ya no se requiere espacio final. :)
Stéphan Kochen
¿No parece acomodar para 'superlongstringstring' en la 2da o posterior posición? (ver descripción del problema)
Nas Banov
2
Eso parece realmente mantenible.
Zombies
39

GolfScript, 177 175 173 167 164 163 144 131 130 caracteres

Lento: 3 minutos para el texto de muestra (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*'| '@}/

Explicación:

{           #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
}/

"Correcto" (con suerte). (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*'| '@}/

Menos lento: medio minuto. (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*'| '@}/

Salida visible en los registros de revisión.

Nabb
fuente
2
Acerca de GolfScript: golfscript.com/golfscript
Assaf Lavie
2
No es correcto, ya que si la segunda palabra es realmente larga, pasará a la siguiente línea.
Gabe
55
"dividir por cero" ... ¿GolfScript lo permite?
JAB
35

206

shell, grep, tr, grep, sort, uniq, sort, head, 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, acabo de ver arriba: sort -nr-> sort -ny luego head-> tail=> 208 :)
update2: erm, por supuesto, lo anterior es una tontería, ya que se revertirá entonces. Entonces, 209.
update3: optimizó la exclusión regexp -> 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$_"'



Por diversión, aquí hay una versión solo para Perl (mucho más rápido):

~ % 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
fuente
35

Solución basada en el conjunto Transact SQL (SQL Server 2005) 1063 892 873 853 827 820 783 683 647 644 630 caracteres

Gracias a Gabe por algunas sugerencias útiles para reducir el recuento de caracteres.

NB: se agregaron saltos de línea para evitar barras de desplazamiento, solo se requiere el último salto de línea.

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 @

Versión legible

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 @

Salida

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

Y con la larga cuerda

 _______________________________________________________________ 
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| Alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| at
|_________________________| with
|_______________________| on
|______________________| all
|____________________| This
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| So
|________________| very
|________________| what
Martin Smith
fuente
12
Te di un +1 porque lo hiciste en T-SQL, y para citar al Equipo América: "Tienes bolas. Me gustan las bolas".
Me tomé la libertad de convertir algunos espacios en nuevas líneas para hacerlo más legible. Espero no haber estropeado las cosas. También lo minimicé un poco más.
Gabe
3
¡Ese código me está gritando! : O
Joey
1
Una buena forma de ahorrar es cambiar 0.000a justo 0y luego usar en -Clugar de 1.0/C. Y haciendo FLOATen REALahorrará un derrame cerebral también. Sin embargo, lo más importante es que parece que tienes muchas ASinstancias que deberían ser opcionales.
Gabe
1
OK, ¿qué tal SELECT [ ] FROM (SELECT $0 O, ' '+REPLICATE('_', MAX(C)*@F)+' ' [ ] FROM # UNION SELECT $1/C, '|'+REPLICATE('_',C*@F)+'| '+W FROM #)X ORDER BY O?
Gabe
34

Ruby 207 213 211 210 207 203 201 200 caracteres

Una mejora en Anurag, incorporando sugerencias de rfusca. También elimina el argumento para ordenar y algunos otros juegos de golf menores.

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} "}

Ejecutar como:

ruby GolfedWordFrequencies.rb < Alice.txt

Editar: poner 'pone' nuevamente, debe estar allí para evitar tener comillas en la salida.
Edit2: archivo modificado-> IO
Edit3: eliminado / i
Edit4: paréntesis eliminados alrededor (f * 1.0), recuento
Edit5: utilice la suma de cadenas para la primera línea; expandirse sen el lugar.
Edit6: hecho m flotante, eliminado 1.0. EDITAR: No funciona, cambia longitudes. EDITAR: No peor que antes
Edit7: Uso STDIN.read.

archgoon
fuente
+1 - me encanta la parte de clasificación, muy inteligente :)
Anurag
Oye, pequeña optimización en comparación con crear la mayor parte en primer lugar. :)
archgoon
¡Agradable! Agregué dos de los cambios que también hice en la versión de Anurag. Afeita otros 4.
Stéphan Kochen
La solución se ha desviado de la salida original, voy a tratar de averiguar dónde sucedió eso.
archgoon
1
Hay una variante más corta de esto más abajo.
archgoon
28

Mathematica ( 297 284 248 244 242 199 caracteres) Funcional puro

y pruebas de la ley de Zipf

Mira mamá ... sin vars, sin manos ... sin cabeza

Edición 1> algunas shorthands definidas (284 caracteres)

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]

Algunas explicaciones

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)

Salida

texto alternativo http://i49.tinypic.com/2n8mrer.jpg

Mathematica no es muy adecuado para el golf, y eso se debe solo a los nombres largos y descriptivos de las funciones. Funciones como "RegularExpression []" o "StringSplit []" solo me hacen sollozar :(.

Prueba de la ley de Zipf

La ley de Zipf predice que para un texto en lenguaje natural, la trama Log (Rank) vs Log (ocurrencias) sigue una relación lineal .

La ley se utiliza en el desarrollo de algoritmos para la criptografía y la compresión de datos. (Pero NO es la "Z" en el algoritmo LZW).

En nuestro texto, podemos probarlo con lo siguiente

 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]

El resultado es (bastante bien lineal)

texto alternativo http://i46.tinypic.com/33fcmdk.jpg

Edición 6> (242 caracteres)

Refactorización de la expresión regular (ya no hay función de selección)
Descartar 1 palabras char
Definición más eficiente para la función "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]

Editar 7 → 199 caracteres

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]
  • Reemplazado fcon Transposey Slot( #1/ #2) argumentos.
  • No necesitamos corchetes apestosos (use en f@xlugar de f[x]donde sea posible)

belisarius
fuente
9
¿Crees que "RegularExpression" es malo? Lloré cuando escribí "System.Text.RegularExpressions.Regex.Split" en la versión C #, hasta que vi el código Objective-C: "stringWithContentsOfFile", "enumerateSubstringsInRange", "NSStringEnumerationByWords", "sortedArrayUsingComparator" y "sortedArrayUsingComparator", y sortedArrayUsingComparator "," sortedArrayUsingComparator "y" sortedArrayUsingComparator ", y sortedArrayUsingComparator", y sortedArrayUsingComparator ", y sortedArrayUsingComparator", y sortedArrayUsingComparator .
Gabe
2
@ Gabe Gracias ... Me siento mejor ahora. En español decimos "mal de muchos, consuelo de tontos". Algo así como "Muchos problemáticos, tontos aliviados": D
Dr. belisarius
1
El |i|es redundante en su expresión regular porque ya lo tiene .|.
Gabe
1
Me gusta ese dicho español. Lo más parecido que puedo pensar en inglés es "la miseria ama la compañía". Aquí está mi intento de traducción: "Es un tonto que, cuando sufre, se consuela al pensar en los demás en la misma situación". Increíble trabajo en la implementación de Mathematica, por cierto.
Dreeves
@dreeves La locura supera fácilmente la barrera del idioma ... Me alegra verte como mi pequeño programa de Mathematica, recién estoy empezando a aprender el idioma
Dr. belisarius
26

C # - 510 451 436 446 434 426 422 caracteres (minificado)

No es tan corto, ¡pero ahora probablemente sea correcto! Tenga en cuenta que la versión anterior no mostraba la primera línea de las barras, no escalaba las barras correctamente, descargaba el archivo en lugar de obtenerlo de stdin y no incluía toda la verbosidad de C # requerida. Podría afeitarse fácilmente muchos trazos si C # no necesitara tanta basura adicional. Quizás Powershell podría hacerlo mejor.

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 caracteres con lendivisor en línea (lo que lo hace 22 veces más lento) en la siguiente forma (líneas nuevas utilizadas para espacios seleccionados):

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
fuente
+1 para los inteligentes que descargan el archivo en línea. :)
sarnold
1
Roba la URL corta de la respuesta de Matt.
indiv
2
La especificación dice que el archivo debe ser canalizado o pasado como un argumento. Si asumiera que args [0] contiene el nombre del archivo local, podría acortarlo considerablemente utilizando args [0] en lugar de (new WebClient ()). DownloadString (@ " gutenberg.org/files/11/11. txt " ) -> te ahorraría aproximadamente 70 caracteres
thorkia
1
Aquí hay una versión que reemplaza la llamada de WebClient con args 0, una llamada a StreamReader y elimina algunos espacios adicionales. Recuento total de caracteres = 413 var a = Regex.Replace ((nuevo StreamReader (args [0])). ReadToEnd (), "[^ a-zA-Z]", "") .ToLower (). Split ('' ) .Where (x =>! (New [] {"the", "and", "of", "to", "a", "i", "it", "in", "or", " es "}). Contiene (x)). GroupBy (x => x). Seleccione (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 ("|" + cadena nueva (' _ ', xc * (80-mwLongitud-4) / mc) + "|" + xw));
thorkia
"nuevo StreamReader" sin "usar" está sucio. File.ReadAllText (args [0]) o Console.In.ReadToEnd () son mucho mejores. En el último caso, incluso puede eliminar el argumento de su Main (). :)
Rotsor
25

Perl 237 229 209 caracteres

(Actualizado nuevamente para vencer a la versión Ruby con más trucos de golf sucios, reemplazando split/[^a-z/,lc con lc=~/[a-z]+/g, y la eliminación de un cheque de cadena vacía en otro lugar. Estos fueron inspirados por la versión de Ruby, por lo que el crédito a quien crédito merece.)

Actualización: ¡ahora con Perl 5.10! Reemplace printcon sayy use ~~para evitar a map. Esto tiene que ser invocado en la línea de comando comoperl -E '<one-liner>' alice.txt . Dado que todo el script está en una línea, escribirlo como una línea no debería presentar ninguna dificultad :).

 @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];

Tenga en cuenta que esta versión se normaliza para el caso. Esto no acorta la solución, ya que eliminar,lc (para la carcasa inferior) requiere que agregue A-Za la expresión regular dividida, por lo que es un lavado.

Si está en un sistema donde una nueva línea es un carácter y no dos, puede acortar esto en otros dos caracteres utilizando una nueva línea literal en lugar de \n . Sin embargo, no he escrito la muestra anterior de esa manera, ya que es "más claro" (¡ja!) De esa manera.


Aquí hay una solución perl mayormente correcta, pero no remotamente corta:

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";
}

Lo siguiente es lo más corto que puede ser mientras se mantiene relativamente legible. (392 caracteres).

%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;
revs JSB ձոգչ
fuente
Tiene algunos errores en este momento; fijación y acortamiento.
JSB ձոգչ
44
Esto no cubre el caso cuando la segunda palabra es mucho más larga que la primera, ¿verdad?
Joey
1
Ambos foreachs se pueden escribir como fors. Eso es 8 caracteres menos. Luego tienes el grep{!($_~~@s)}map{lc=~/[a-z]+/g}<>, que creo que podría escribirse grep{!(/$_/i~~@s)}<>=~/[a-z]+/gpara ir 4 más abajo. Reemplace " "con $"y estás abajo 1 más ...
Zaid
sort{$c{$b}-$c{$a}}...para salvar dos más. También puede pasar en %clugar de keys %ca la sortfunción y guardar cuatro más.
mafia
20

Windows PowerShell, 199 caracteres

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

(El último salto de línea no es necesario, pero se incluye aquí para facilitar la lectura).

(El código actual y mis archivos de prueba están disponibles en mi repositorio SVN . Espero que mis casos de prueba detecten los errores más comunes (longitud de la barra, problemas con la coincidencia de expresiones regulares y algunos otros))

Suposiciones

  • ASCII de EE. UU. Como entrada. Probablemente se pone raro con Unicode.
  • Al menos dos palabras sin parar en el texto

Historia

Versión relajada (137), ya que eso se cuenta por separado por ahora, aparentemente:

($x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *)[-1..-22]|%{"|$('_'*(76*$_.Count/$x[-1].Count))| "+$_.Name}
  • no cierra la primera barra
  • no tiene en cuenta la longitud de palabra de la primera palabra

Las variaciones de las longitudes de barra de un carácter en comparación con otras soluciones se deben a que PowerShell utiliza redondeo en lugar de truncamiento al convertir números de punto flotante en enteros. Sin embargo, dado que la tarea solo requería una longitud de barra proporcional, esto debería estar bien.

En comparación con otras soluciones, tomé un enfoque ligeramente diferente para determinar la longitud de barra más larga simplemente probando y tomando la longitud más alta en la que ninguna línea tiene más de 80 caracteres.

Una versión anterior explicada se puede encontrar aquí .

descuento
fuente
Impresionante, parece que Powershell es un entorno adecuado para el golf. Su enfoque teniendo en cuenta la longitud de la barra es exactamente lo que intenté describir (no tan brillantemente, lo admito) en la especificación.
ChristopheD
1
@ChristopheD: En mi experiencia (Anarchy Golf, algunas tareas del Proyecto Euler y algunas tareas más solo por diversión), PowerShell suele ser solo un poco peor que Ruby y, a menudo, está vinculado o es mejor que Perl y Python. Sin embargo, no hay rival para GolfScript. Pero por lo que puedo ver, esta podría ser la solución más corta que tenga en cuenta correctamente las longitudes de barra ;-)
Joey
Aparentemente tenía razón. Powershell puede hacerlo mejor, ¡mucho mejor! Proporcione una versión ampliada con comentarios.
Gabe
Johannes: ¿Lo intentaste -split("\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z]")? Esto funciona para mi.
Gabe
No olvides interpolar la cadena de salida: "|$('_'*($w*$_.count/$x[0].count))| $($_.name) "(o eliminar el último espacio, ya que es algo automático). Y puede usar -split("(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z])+")para guardar algunos más al no incluir espacios en blanco (o uso [-2..-23]).
Gabe
19

Ruby, 215, 216 , 218 , 221 , 224 , 236 , 237 caracteres

actualización 1: ¡ Hurra ! Es un empate con la solución de JS Bangs . No puedo pensar en una forma de reducir más :)

Actualización 2: jugué un truco de golf sucio. Cambiado eacha mappara guardar 1 personaje :)

Actualización 3: cambiado File.reada IO.read+2. Array.group_byno fue muy fructífero, cambió a reduce+6. No es necesaria una comprobación de mayúsculas y minúsculas después de la carcasa inferior con downcaseregex +1. La clasificación en orden descendente se realiza fácilmente al negar el valor +6. Ahorro total +15

actualización 4: en [0]lugar de .first+3. (@ Shtééf)

Actualización 5: expandir la variable len el lugar, +1. Expandir variable sen el lugar, +2. (@ Shtééf)

Actualización 6: Use la suma de cadenas en lugar de la interpolación para la primera línea, +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} "}

Actualización 7: pasé por un montón de hoopla para detectar la primera iteración dentro del bucle, usando variables de instancia. Todo lo que obtuve es +1, aunque quizás haya potencial. Preservar la versión anterior, porque creo que esta es magia negra. (@ 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} "}

Versión legible

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

Usar:

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

Salida:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
Anurag
fuente
3
¿No es "p" un atajo para "pone"? Eso podría afeitar algunos.
rfusca
1
Agradable. Sin scanembargo, su uso me dio una mejor idea, así que me adelanté otra vez :).
JSB ձոգչ
2
Debe escalar las barras para que la palabra más larga más su barra se ajuste a 80 caracteres. Como Brian sugirió, una segunda palabra larga romperá su programa.
Gabe
3
Me pregunto por qué esto sigue reuniendo votos. La solución es incorrecta (en el caso general) y las soluciones Ruby de dos vías más cortas ya están aquí.
Joey
1
Ahora, corrígeme si estoy equivocado, pero en lugar de usar "downcase", ¿por qué no usas la bandera que no distingue entre mayúsculas y minúsculas REGEXP, que ahorra de 6 a 7 bytes?
st0le
19

Python 2.x, enfoque latitudinariano = 227183 caracteres

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

Permitiendo libertad en la implementación, construí una concatenación de cadenas que contiene todas las palabras solicitadas para exclusión ( the, and, of, to, a, i, it, in, or, is), además de que también excluye las dos "palabras" infames sy tdel ejemplo, y arrojé la exclusión gratis an, for, he. Intenté todas las concatenaciones de esas palabras contra el corpus de las palabras de Alicia, la Biblia del Rey James y el archivo de la jerga para ver si hay alguna palabra que la cadena excluya erróneamente. Y así es como terminé con dos cadenas de exclusión: itheandtoforinisy andithetoforinis.

PD. prestado de otras soluciones para acortar el código.

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

Despotricar

Con respecto a las palabras a ignorar, uno pensaría que se tomarían de la lista de las palabras más usadas en inglés. Esa lista depende del corpus de texto utilizado. Según una de las listas más populares ( http://en.wikipedia.org/wiki/Most_common_words_in_English , http://www.english-for-students.com/Frequency-Used-Words.html , http: // www. sporcle.com/games/common_english_words.php ), las 10 palabras principales son:the be(am/are/is/was/were) to of and a in that have I

Las 10 palabras principales del texto Alicia en el país de las maravillas son the and to a of it she i you said
Las 10 palabras principales del archivo de jerga (v4.4.7) sonthe a of to and in is that or for

Entonces, la pregunta es por qué orse incluyó en la lista de ignorar del problema, donde es ~ 30 en popularidad cuando la palabrathat (el octavo más utilizado) no lo es. etc, etc. Por lo tanto, creo que la lista de ignorados debería proporcionarse dinámicamente (o podría omitirse).

La idea alternativa sería simplemente omitir las 10 palabras principales del resultado, lo que en realidad acortaría la solución (elemental, tiene que mostrar solo las entradas 11 a 32).


Python 2.x, enfoque puntiagudo = 277 243 caracteres

El gráfico dibujado en el código anterior se simplifica (usando solo un carácter para las barras). Si se desea reproducir exactamente el gráfico de la descripción del problema (que no era obligatorio), este código lo hará:

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

Tengo un problema con la elección algo aleatoria de las 10 palabras para excluir, the, and, of, to, a, i, it, in, or, ispor lo que se deben pasar como parámetros de línea de comando, así:
python WordFrequencyChart.py the and of to a i it in or is <"Alice's Adventures in Wonderland.txt"

Esto es 213 caracteres + 30 si tenemos en cuenta la lista de ignorados "original" pasada en la línea de comando = 243

PD. El segundo código también "ajusta" las longitudes de todas las palabras principales, por lo que ninguna de ellas se desbordará en caso degenerado.

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|_____________________________________________________| said
|______________________________________________| alice
|_________________________________________| was
|______________________________________| that
|_______________________________| as
|____________________________| her
|__________________________| at
|__________________________| with
|_________________________| s
|_________________________| t
|_______________________| on
|_______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|___________________| not
|_________________| they
|_________________| so
Nas Banov
fuente
Buena solución hasta ahora, aunque la palabra ignorar lista no está implementada (todavía) y las barras son un poco rudimentarias en este momento.
ChristopheD
@ChristopheD: estaba allí, pero no había una "guía del usuario". Recién agregado texto de grupo
Nas Banov
Con respecto a su lista de idiomas y soluciones: busque soluciones que utilicen dividir a lo largo \Wo usar \ben una expresión regular porque es muy probable que no estén de acuerdo con las especificaciones, lo que significa que no se dividirán en dígitos o _que tampoco eliminarán las palabras vacías de las cadenas tales como the_foo_or123bar. Puede que no aparezcan en el texto de prueba, pero la especificación es bastante clara en ese caso.
Joey
Increíble trabajo Nas, pasé una tarde tratando de optimizar esto y solo encontré una mejora. Puede sys.argvre.findall(r'\b(?!(?:the|and|.|of|to|i[tns]|or)\b)\w+',sys.stdin.read().lower())
reducirlo
12

Haskell - 366 351 344 337 333 caracteres

(Se mainagregó un salto de línea para facilitar la lectura, y no se necesita un salto de línea al final de la última línea).

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

La mejor manera de ver cómo funciona es leyendo el argumento al interactrevés:

  • map f alfabéticos en minúsculas, reemplaza todo lo demás con espacios.
  • words produce una lista de palabras, dejando caer el espacio en blanco de separación.
  • filter (notElem words "the and of to a i it in or is")descarta todas las entradas con palabras prohibidas.
  • group . sort ordena las palabras y agrupa las idénticas en listas.
  • map hasigna cada lista de palabras idénticas a una tupla del formulario (-frequency, word).
  • take 22 . sort clasifica las tuplas por frecuencia descendente (la primera entrada de tuplas) y mantiene solo las primeras 22 tuplas.
  • b asigna tuplas a barras (ver más abajo).
  • a antepone la primera línea de guiones bajos para completar la barra superior.
  • unlines une todas estas líneas junto con nuevas líneas.

Lo difícil es obtener la longitud correcta de la barra. Supuse que solo los guiones bajos contaban para la longitud de la barra, por ||lo que sería una barra de longitud cero. La función de blos mapas c xmás x, donde xes la lista de los histogramas. La lista completa se pasa a c, de modo que cada invocación de cpueda calcular el factor de escala por sí mismo llamandou . De esta manera, evito usar matemática de punto flotante o racionales, cuyas funciones de conversión e importaciones se comerían muchos caracteres.

Tenga en cuenta el truco de usar -frequency. Esto elimina la necesidad de reversela sortya de clasificación (ascendente) -frequencyse coloca las palabras con la frecuencia descendiente. Más tarde, en la función u, -frequencyse multiplican dos valores, lo que cancelará la negación.

Thomas
fuente
Muy buen trabajo (votaría a favor pero se quedó sin votos para hoy con todas las excelentes respuestas en este hilo).
ChristopheD
Esto me duele los ojos de una manera que es dolorosa incluso pensar en describir, pero aprendí mucho de Haskell mediante ingeniería inversa en un código legible. Bien hecho, señor. :-)
Owen S.
Todavía es bastante idiomático Haskell, aunque no es realmente eficiente. Los nombres cortos hacen que se vea mucho peor de lo que realmente es.
Thomas
@Thomas: Puedes decir eso otra vez. :-)
Owen S.
1
No se puede mover el div, en realidad! Pruébalo, la salida es incorrecta. La razón es que hacer lo divanterior *pierde precisión.
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)}

Lamentablemente, la for([k,v]in z)versión de Rhino no parece querer trabajar en SpiderMonkey, y readFile()es un poco más fácil que usarla, readline()pero pasar a 1.8 nos permite usar cierres de funciones para cortar algunas líneas más ...

Agregar espacios en blanco para facilitar la lectura:

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)
}

Uso: js golf.js < input.txt

Salida:

 _________________________________________________________________________ 
| _________________________________________________________________________ | ella
| _______________________________________________________________ | tú
| ____________________________________________________________ | dijo
| ____________________________________________________ | Alicia
| ______________________________________________ | estaba
| ___________________________________________ | ese
| ___________________________________ | como
| ________________________________ | su
| _____________________________ | a
| _____________________________ | con
| ____________________________ | s
| ____________________________ | t
| __________________________ | en
| _________________________ | todas
| _______________________ | esta
| ______________________ | para
| ______________________ | tenido
| ______________________ | pero
| _____________________ | ser
| _____________________ | no
| ___________________ | ellos
| ___________________ | entonces

(versión base - no maneja los anchos de barra correctamente)

JavaScript (Rhino) - 405 395 387 377 368 343 304 caracteres

Creo que mi lógica de clasificación está apagada, pero ... lo sé. Brainfart arreglado.

Minified (abuso que se \ninterpreta como a ;veces):

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)}
Matt
fuente
Ah señor. Creo que este es tu guante. Haz que tu segundo hable con el mío.
dmckee --- ex-gatito moderador el
2
Por cierto, me gusta la i[tns]?parte. Muy astuto
dmckee --- ex-gatito moderador
@dmckee - bien jugado, no creo que pueda vencer a tus 336, disfruta de tu muy merecido voto :)
Matt
Definitivamente puedes vencer a 336 ... Hay un corte de 23 caracteres disponible - .replace(/[^\w ]/g, e).split(/\s+/).map(puede ser reemplazado .replace(/\w+/g,y usar la misma función que .maptuviste ... Tampoco estoy seguro si Rhino admite en function(a,b)b.c-a.clugar de tu función de clasificación (spidermonkey sí), pero eso será afeitado {return }... b.c-a.ces un mejor tipo que a.c<b.cpor cierto ... Edición de una versión de Mono Araña en la parte inferior con estos cambios
gnarf
Moví mi versión de SpiderMonkey a la parte superior ya que se ajusta a la restricción de ancho de barra ... También logré cortar algunos caracteres más en su versión original mediante el uso de una expresión regular negativa para negar palabras que permitan un solo reemplazo (), ¡Y jugué golf con unos pocos con ?:gran base para trabajar!
gnarf
11

Versión de PHP CLI (450 caracteres)

Esta solución tiene en cuenta el último requisito que la mayoría de los puristas han optado por ignorar. ¡Eso costó 170 caracteres!

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

Minified:

<?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";?>

Legible por humanos:

<?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";

?>

Salida:

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

Cuando hay una palabra larga, las barras se ajustan correctamente:

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

Python 3.1 - 245 229 caracteres

Supongo que usar Counter es una especie de trampa :) Acabo de leerlo hace una semana, así que esta fue la oportunidad perfecta para ver cómo funciona.

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

Parte del código fue "prestado" de la solución de AKX.

sdolan
fuente
Falta la primera línea. Y la longitud de la barra no es correcta.
Joey
en su código parece que se open('!')lee desde stdin, ¿en qué versión / OS está? o tienes que nombrar el archivo '!'
Nas Banov
Nombre el archivo "!" :) Lo siento, eso no estaba claro, y debería haberlo mencionado.
Sam Dolan
11

Perl, 205 191 189 caracteres / 205 caracteres (totalmente implementado)

Algunas partes se inspiraron en las presentaciones anteriores de perl / ruby, se llegaron a un par de ideas similares de forma independiente, las otras son originales. La versión más corta también incorpora algunas cosas que vi / aprendí de otras presentaciones.

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];

Última versión de hasta 191 caracteres:

/^(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]

Última versión de hasta 189 caracteres:

/^(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]

Esta versión (205 caracteres) representa las líneas con palabras más largas que las que se encontrarían más adelante.

/^(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]
revs pdehaan
fuente
10

Perl: 203 202 201 198 195 208 203/231 caracteres

$/=\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]

Implementación alternativa completa que incluye el comportamiento indicado (compresión global de barras) para el caso patológico en el que la palabra secundaria es popular y lo suficientemente larga como para combinarse con más de 80 caracteres ( esta implementación es de 231 caracteres ):

$/=\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 especificación no indicaba en ninguna parte que esto tenía que ir a STDOUT, por lo que utilicé perl's warn () en lugar de print: cuatro caracteres guardados allí. Usé el mapa en lugar de foreach, pero siento que aún podría haber más ahorros en la división (join ()). Aún así, lo bajé a 203, podría dormir sobre él. Al menos Perl está ahora bajo el recuento de caracteres "shell, grep, tr, grep, sort, uniq, sort, head, perl" por ahora;)

PD: Reddit dice "Hola";)

Actualización: Se eliminó la combinación () a favor de la asignación y la combinación de conversión escalar implícita. Hasta 202. También tenga en cuenta que he aprovechado la regla opcional "ignorar palabras de 1 letra" para eliminar 2 caracteres, así que tenga en cuenta que el conteo de frecuencias reflejará esto.

Actualización 2: Se cambió la asignación y la unión implícita por matar $ / para obtener el archivo de una vez usando <> en primer lugar. Mismo tamaño, pero más desagradable. Se cambia si (! $ Y) {} por $ y || {} &&, guarda 1 char más> 201.

Actualización 3: Tomé el control de las minúsculas temprano (lc <>) al mover lc fuera del bloque del mapa - Cambié ambas expresiones regulares para no usar más la opción / i, ya que ya no era necesario. Construcción condicional explícita intercambiada x? Y: z para perlgolf tradicional || construcción condicional implícita - /^...$/i?1:$x{$ } ++ para /^...$/||$x{$ } ++ ¡Guardado tres caracteres! => 198, rompió la barrera de 200. Podría dormir pronto ... tal vez.

Actualización 4: la falta de sueño me ha vuelto loco. Bien. Más loco. Suponiendo que esto solo tiene que analizar los archivos normales de texto feliz, hice que renunciara si llega a un valor nulo. Guardado dos personajes. Reemplazado "length" por el 1-char más corto (y mucho más golfish) y /// c - ¿me escuchas, GolfScript? Voy por ti !!! sollozo

Actualización 5: Sleep Dep me hizo olvidar el límite de 22 hileras y la limitación de la línea posterior. Retroceda hasta 208 con los manejados. No está mal, 13 personajes para manejarlo no es el fin del mundo. Jugué con la evaluación en línea de expresiones regulares de perl, pero tuve problemas para que funcione y ahorre caracteres ... jaja. Se actualizó el ejemplo para que coincida con la salida actual.

Actualización 6: Se eliminaron los brackets innecesarios que protegen (...), ya que el candy sintáctico ++ permite empujarlo contra el para felizmente. Gracias a las aportaciones de Chas. Owens (recordando mi cerebro cansado), obtuvo la solución de clase de personaje i [tns] allí. De vuelta a 203.

Actualización 7: Se agregó un segundo trabajo, implementación completa de especificaciones (incluido el comportamiento de barra de compresión completa para palabras largas secundarias, en lugar del truncamiento que está haciendo la mayoría de las personas, según la especificación original sin el caso de ejemplo patológico)

Ejemplos:

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

Implementación alternativa en caso de caso patológico:

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| with
|_________________________| at
|_______________________| on
|______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| so
|________________| very
|________________| what
Syntaera
fuente
Puede acortar la expresión regular para las palabras vacías por el colapso is|in|it|ien i[snt]?- y luego no hay ninguna diferencia con la regla opcional más. (Hm, nunca habría pensado en decirle a un chico de Perl cómo hacer Regex: D). Solo tengo un problema ahora: tengo que ver cómo puedo eliminar tres bytes de mi propia solución para ser mejor que Perl nuevamente: - |
Joey
Ok, ignore parte de lo que dije antes. Ignorar palabras de una letra es, de hecho, un byte más corto que no hacerlo.
Joey
Cada byte cuenta;) consideré hacer el truco de la nueva línea, pero pensé que en realidad era la misma cantidad de bytes, incluso si se trataba de menos caracteres imprimibles. Todavía estoy trabajando para ver si puedo reducirlo un poco más :)
Syntaera
Ah, bueno, la normalización de casos me devolvió a 209. No veo qué más podría cortar. Aunque PowerShell puede ser más corto que Perl. ;-)
Joey el
No veo dónde restringe la salida a las 22 palabras principales, ni dónde se asegura de que una segunda palabra larga no se ajuste.
Gabe
9

F #, 452 caracteres

Fácil: obtenga una secuencia ade pares de conteo de palabras, encuentre el mejor multiplicador de conteo de palabras por columna k, luego imprima los resultados.

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

Ejemplo (tengo recuentos de frecuencia diferentes a los tuyos, sin saber por qué):

% 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
fuente
Resulta que mi propia solución estaba un poco apagada (debido a una pequeña especificación diferente), las soluciones corresponden ahora ;-)
ChristopheD
+1 para la única implementación correcta de escalado de barras hasta el momento
Rotsor
2
(@Rotsor: Ironic, dado que la mía es la solución más antigua.)
Brian
Apuesto a que podría acortarlo un poco fusionando las etapas de división, mapa y filtro. También esperaría que no necesitaras tantos floats.
Gabe
¿Las funciones de anidamiento no suelen ser más cortas que usar el operador de canalización |>?
Joey
8

Python 2.6, 347 caracteres

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

Salida:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
AKX
fuente
1
Puede perder la línea bm=(76.-len(W[0][0]))/W[0][1]ya que solo está usando bm una vez (haga la siguiente línea U=lambda n:"_"*int(n*(76.-len(W[0][0]))/W[0][1]), elimina 5 caracteres. Además: ¿por qué usaría un nombre de variable de 2 caracteres en golf de código? ;-)
ChristopheD el
En la última línea, el espacio después de la impresión no es necesario, elimina un carácter
ChristopheD
1
No considera el caso cuando la segunda palabra más frecuente es muy larga, ¿verdad?
Joey
@ChristopheD: Porque había estado mirando ese código durante demasiado tiempo. : P Buena captura. @Johannes: Eso también podría arreglarse, sí. Tampoco estoy seguro de que todas las demás implementaciones lo hicieran cuando escribí esto.
AKX
7

* sh (+ curl), solución parcial

Esto está incompleto, pero por el simple hecho, aquí está la mitad del problema de conteo de frecuencia de palabra en 192 bytes:

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

Gawk - 336 (originalmente 507) caracteres

(después de arreglar el formato de salida; arreglar lo de las contracciones; ajustar; ajustar de nuevo; eliminar un paso de clasificación completamente innecesario; ajustar una y otra vez; y otra vez (Ups, este rompió el formato); ajustar un poco más; asumiendo el desafío de Matt, modifico desesperadamente mucho más; encontré otro lugar para guardar algunos, pero devolví dos para corregir el error de longitud de la barra)

¡Je je! ¡Estoy momentáneamente por delante del desafío de contador de soluciones [Matt's JavaScript] [1] ! ;) y [la pitón de AKX] [2].

El problema parece requerir un lenguaje que implemente matrices asociativas nativas, por lo que, por supuesto , he elegido uno con un conjunto de operadores terriblemente deficientes. En particular, no puede controlar el orden en que awk ofrece los elementos de un mapa hash, por lo que escaneo repetidamente todo el mapa para encontrar el elemento más numeroso actualmente, imprimirlo y eliminarlo de la matriz.

Todo es terriblemente ineficiente, con todas las vacaciones de golf que he hecho también ha resultado ser bastante horrible.

Minified:

{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]}}

saltos de línea solo por claridad: no son necesarios y no deben contarse.


Salida:

$ 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

Legible; 633 caracteres (originalmente 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
fuente
Buen trabajo, bueno, incluiste una versión con sangría / comentada ;-)
ChristopheD el
7

LISP común, 670 caracteres

Soy un novato de LISP, y este es un intento de usar una tabla hash para contar (por lo que probablemente no sea el método más compacto).

(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)))))

se puede ejecutar por ejemplo con cat alice.txt | clisp -C golf.lisp.

En forma legible es

(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
fuente
¿Has intentado instalar una macro de lector personalizado para reducir el tamaño de entrada?
Aaron
@Aaron en realidad no fue trivial para mí, incluso si esto funcionaba ... :-) para la parte de golf real, solo usé variables de una letra y eso es todo. De todos modos, además de la verbosidad algo alta que es inherente a CL para esta escala de problemas ("concatenate 'string", "setf" o "gethash" son asesinos ... en python son "+", "=", "[]" ) aún así me sentí mucho peor de lo que hubiera esperado incluso en un nivel lógico. En cierto sentido, tengo la sensación de que lisp está bien, pero el lisp común es regular y esto va más allá de nombrarlo (releerlo es un comentario muy injusto ya que mi experiencia con CL es cercana a cero).
6502
cierto. esquema haría el golf un poco más fácil, con el espacio de nombres único. en lugar de string-append por todo el lugar, podrías (letrec ((a string-append) (b gethash)) ... (a "x" "yz") ...)
Aaron
6

C (828)

Se parece mucho al código ofuscado, y usa glib para string, list y hash. Char cuenta con wc -mdice 828 . No considera palabras de un solo carácter. Para calcular la longitud máxima de la barra, considere la palabra más larga posible entre todas, no solo las primeras 22. ¿Es esta una desviación de la especificación?

No maneja fallas y no libera memoria usada.

#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);}
revs ShinTakezou
fuente
Las líneas nuevas sí cuentan como caracteres, pero puede quitar cualquiera de las líneas que no son instrucciones del preprocesador. Para un golf, no consideraría no liberar la memoria como una mala práctica.
Stéphan Kochen el
ok ... coloque todo en una línea (espere macros de preprocesamiento) y reciba un vers sin liberar mem (y con otros dos espacios eliminados ... se puede hacer un poco de mejora en la "ofuscación", por ejemplo *v=*v*(77-lw)/m, dará 929. .. pero creo que puede estar bien a menos que encuentre una manera de hacerlo mucho más corto)
ShinTakezou
Creo que se puede mover al menos la int cen la maindeclaración y mainestá implícitamente int(como lo son los argumentos sin tipo, que yo sepa): main(c){...}. Probablemente también podrías escribir en 0lugar de NULL.
Joey
hacerlo ... por supuesto activará alguna advertencia con -Wallo con la -std=c99bandera encendida ... pero supongo que esto no tiene sentido para un código de golf, ¿verdad?
ShinTakezou
uff, perdón por las ediciones breves, ... Debería cambiar Without freeing memory stuff, it reaches 866 (removed some other unuseful space)a otra cosa para no dejar que la gente piense que la diferencia con la versión de memoria libre es todo eso: ahora la versión sin memoria libre tiene muchas más "mejoras".
ShinTakezou
6

Perl, 185 char

200 (ligeramente roto) 199 197 195 193 187 185 caracteres. Las dos últimas líneas nuevas son significativas. Cumple con la especificación.

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 primera línea carga conteos de palabras válidas en %X.

La segunda línea calcula el factor de escala mínimo para que todas las líneas de salida sean <= 80 caracteres.

La tercera línea (contiene dos caracteres de nueva línea) produce la salida.

mob
fuente
Esto no eliminará palabras de detención de cadenas como "foo_the_bar". La longitud de la línea también es demasiado larga (vuelva a leer la especificación: "barra + espacio + palabra + espacio <= 80 caracteres")
Joey
5

Java - 886 865 756 744 742 744 752 742 714 680 caracteres

  • Actualizaciones antes del primer 742 : expresiones regulares mejoradas, tipos parametrizados superfluos eliminados, espacios en blanco superfluos eliminados.

  • Actualización 742> 744 caracteres : reparó el hack de longitud fija. Solo depende de la primera palabra, no de otras palabras (todavía). Encontró varios lugares para acortar el código ( \\sen regex reemplazado por y ArrayListreemplazado por Vector). Ahora estoy buscando una forma corta de eliminar la dependencia de IO de Commons y leer de stdin.

  • Actualización 744> 752 caracteres : eliminé la dependencia de los comunes. Ahora se lee de stdin. Pegue el texto en stdin y presione Ctrl+Zpara obtener el resultado.

  • Actualización 752> 742 caracteres : eliminépublic y un espacio, hice classname 1 char en lugar de 2 y ahora ignora las palabras de una letra.

  • Actualización 742> 714 caracteres : actualizado según los comentarios de Carl: se eliminó la asignación redundante (742> 730), se reemplazó m.containsKey(k)por m.get(k)!=null(730> 728), se introdujo la subcadena de la línea (728> 714).

  • Actualización 714> 680 caracteres : actualizado según los comentarios de Rotsor: cálculo de tamaño de barra mejorado para eliminar fundición innecesaria y mejorado split()para eliminar innecesaria 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);}}

Versión más legible:

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);
 }
}

Salida:

 _________________________________________________________________________
| _________________________________________________________________________ | ella
| _______________________________________________________________ | tú
| ____________________________________________________________ | dijo
| _____________________________________________________ | Alicia
| _______________________________________________ | estaba
| ___________________________________________ | ese
| ____________________________________ | como
| ________________________________ | su
| _____________________________ | con
| _____________________________ | a
| __________________________ | en
| __________________________ | todas
| _______________________ | esta
| _______________________ | para
| _______________________ | tenido
| _______________________ | pero
| ______________________ | ser
| _____________________ | no
| ____________________ | ellos
| ____________________ | entonces
| ___________________ | muy
| __________________ | qué

Bastante apesta que Java no tenga String#join()y cierres (todavía).

Editar por Rotsor:

He realizado varios cambios en su solución:

  • Lista reemplazada con una cadena []
  • Reutilicé el argumento 'args' en lugar de declarar mi propia matriz de cadenas. También lo usé como argumento para .ToArray ()
  • Reemplazado StringBuffer con un String (sí, sí, rendimiento terrible)
  • Se reemplazó la ordenación de Java con una selección de clasificación con detención temprana (solo se deben encontrar los primeros 22 elementos)
  • Agregó alguna declaración int en una sola declaración
  • Implementé el algoritmo no engañoso para encontrar la línea de salida más limitante. Implementado sin FP.
  • Se corrigió el problema del bloqueo del programa cuando había menos de 22 palabras distintas en el texto
  • Implementé un nuevo algoritmo de lectura de entrada, que es rápido y solo 9 caracteres más largo que el lento.

El código condensado tiene 688 711 684 caracteres de longitud:

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 versión rápida ( 720 693 caracteres)

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);}}}

Versión más legible:

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 versión sin mejoras de comportamiento es de 615 caracteres:

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
fuente
¿No podría usar el nombre completo en IOUtilslugar de importarlo? Hasta donde puedo ver, de todos modos lo estás usando solo una vez.
Joey
55
Engañaste al suponer que la barra más larga tendrá exactamente 75 caracteres. Debe asegurarse de que ninguna barra + palabra tenga más de 80 caracteres.
Gabe
Te estás perdiendo un espacio después de la palabra. ;)
st0le
Mientras recortaba mi respuesta , esperaba superar la sumisión de BalusC. Todavía tengo 200 personajes para ir, ugh! Me pregunto cuánto tiempo pasaría sin la suposición de Char IO y 75 de Commons.
Jonathon Faust
1
Parece que podrías afeitar algunos personajes haciendo bun String en lugar de un StringBuffer. Sin embargo, no quiero pensar en cuál sería la actuación (especialmente porque está agregando un personaje a la vez).
Michael Myers
4

Scala 2.8, 311 314 320 330 332 336 341 375 caracteres

incluyendo el ajuste de palabras largas. Ideas tomadas de las otras soluciones.

Ahora como un 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)

Corre con

scala -howtorun:script a.scala alice.txt

Por cierto, la edición de 314 a 311 caracteres en realidad elimina solo 1 carácter. Alguien se equivocó al contar antes (¿CR de Windows?).

mkneissl
fuente
4

Clojure 282 estricto

(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)))

Algo más legible:

(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
fuente
4

Scala, 368 caracteres

Primero, una versión legible en 592 caracteres:

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 salida de la consola se ve así:

$ 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

Podemos hacer una minificación agresiva y reducirla a 415 caracteres:

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 sesión de la consola se ve así:

$ 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

Estoy seguro de que un experto en Scala podría hacerlo aún mejor.

Actualización: En los comentarios, Thomas dio una versión aún más corta, con 368 caracteres:

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

Legiblemente, a 375 caracteres:

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
fuente
383 caracteres: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
Por supuesto, ¡siempre útil para la comprensión! ¡Agradable!
pr1001
3

Java - 896 caracteres

931 caracteres

1233 caracteres hechos ilegibles

1977 caracteres "sin comprimir"


Actualización: reduje agresivamente el recuento de caracteres. Omite palabras de una letra por especificación actualizada.

Envidio mucho a C # y 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)+" ");}}}

"Legible":

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)+" ");
      }
   }
}

Salida de Alice:

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

Salida de Don Quijote (también 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
fuente
8
Totalmente carpa, ¿realmente no hay forma de acortarlo en Java? Espero que les paguen por número de caracteres y no por funcionalidad :-)
Nas Banov