Crie um gráfico ASCII das palavras mais usadas em um determinado texto [fechado]

156

O desafio:

Crie um gráfico ASCII das palavras mais usadas em um determinado texto.

As regras:

  • Aceite apenas a-ze A-Z(caracteres alfabéticos) como parte de uma palavra.
  • Ignore a caixa ( She== shepara nosso propósito).
  • Ignore as seguintes palavras (bastante arbitrárias, eu sei): the, and, of, to, a, i, it, in, or, is
  • Esclarecimento: considerando don't: isso seria considerado como 2 'palavras' diferentes nos intervalos a-ze A-Z: ( done t).

  • Opcionalmente (é tarde demais para alterar formalmente as especificações agora), você pode optar por descartar todas as 'palavras' de uma única letra (isso pode potencialmente reduzir também a lista de ignorados).

Analise um dado text(leia um arquivo especificado por meio de argumentos de linha de comando ou canalizado; presuma us-ascii) e construa-o word frequency chartcom as seguintes características:

  • Exiba o gráfico (também veja o exemplo abaixo) para as 22 palavras mais comuns (ordenadas por frequência descendente).
  • A barra widthrepresenta o número de ocorrências (frequência) da palavra (proporcionalmente). Acrescente um espaço e imprima a palavra.
  • Certifique-se de que essas barras (mais espaço-palavra-espaço) sempre se ajustem : bar+ [space]+ word+ [space]deve sempre ter <= 80caracteres (certifique-se de ter em conta possíveis comprimentos diferentes de barra e palavra: por exemplo: a segunda palavra mais comum pode demorar muito mais do que o primeiro, embora não diferindo tanto em frequência). Maximize a largura da barra dentro dessas restrições e dimensione as barras adequadamente (de acordo com as frequências que elas representam).

Um exemplo:

O texto para o exemplo pode ser encontrado aqui ( Alice no país das maravilhas, por Lewis Carroll ).

Esse texto específico produziria o seguinte gráfico:

 _________________________________________________________________________
| _________________________________________________________________________ | ela
| _______________________________________________________________ | vocês
| ____________________________________________________________ | disse
| ____________________________________________________ | Alice
| ______________________________________________ | foi
| __________________________________________ | aquele
| ___________________________________ | Como
| _______________________________ | dela
| ____________________________ | com
| ____________________________ | às
| ___________________________ | s
| ___________________________ | t
| _________________________ | em
| _________________________ | tudo
| ______________________ | isto
| ______________________ | para
| ______________________ | teve
| _____________________ | mas
| ____________________ | estar
| ____________________ | não
| ___________________ | eles
| __________________ | tão


Para sua informação: estas são as frequências nas quais o gráfico acima se baseia:

[('she', 553), ('you', 481), ('said', 462), ('alice', 403), ('was', 358), ('que
', 330), (' as ', 274), (' her ', 248), (' with ', 227), (' at ', 227), (' s ', 219), (' t '
, 218), ('on', 204), ('all', 200), ('this', 181), ('for', 179), ('had', 178), ('
mas ', 175), (' ser ', 167), (' não ', 166), (' eles ', 155), (' so ', 152)]

Um segundo exemplo (para verificar se você implementou a especificação completa): Substitua todas as ocorrências do arquivo Alice no país das maravilhasyou vinculado por :superlongstringstring

 ________________________________________________________________
| ________________________________________________________________ | ela
| _______________________________________________________ | superlongstringstring
| _____________________________________________________ | disse
| ______________________________________________ | Alice
| ________________________________________ | foi
| _____________________________________ | aquele
| ______________________________ | Como
| ___________________________ | dela
| _________________________ | com
| _________________________ | às
| ________________________ | s
| ________________________ | t
| ______________________ | em
| _____________________ | tudo
| ___________________ | isto
| ___________________ | para
| ___________________ | teve
| __________________ | mas
| _________________ | estar
| _________________ | não
| ________________ | eles
| ________________ | tão

O vencedor:

Solução mais curta (por contagem de caracteres, por idioma). Diverta-se!


Edit : Tabela resumindo os resultados até o momento (15/02/2012) (adicionado originalmente pelo usuário Nas Banov):

Idioma Relaxado Estrito
========= ======= ======
GolfScript 130 143
Perl 185
Windows PowerShell 148 199
Mathematica 199
Ruby 185 205
Ferramenta Unix 194 228
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

Os números representam o comprimento da solução mais curta em um idioma específico. "Estrito" refere-se a uma solução que implementa completamente as especificações (desenha |____|barras, fecha a primeira barra no topo com uma ____linha, explica a possibilidade de palavras longas com alta frequência, etc.). "Relaxado" significa que algumas liberdades foram tomadas para reduzir a solução.

Somente soluções menores que 500 caracteres estão incluídas. A lista de idiomas é classificada pelo tamanho da solução 'estrita'. 'Unix Toolchain' é usado para significar várias soluções que usam o shell * nix tradicional mais uma mistura de ferramentas (como grep, tr, sort, uniq, head, perl, awk).

ChristopheD
fonte
4
Bem, 'barra mais longa' + palavra = 80 pode não caber dentro de 80 cols se a segunda palavra mais comum for uma palavra muito mais longa. Estou procurando a 'restrição máxima', eu acho.
Brian
1
Normalizamos o revestimento? 'Ela' = 'ela'?
Brian
2
O desempenho da IMO, tanto em termos de tempo de execução quanto de uso de memória, parece ser um desafio mais interessante do que a contagem de caracteres.
Frank Farmer
81
Fico feliz em ver que minhas palavras favoritas se testão representadas.
indiv
8
@indiv, @Nas Banov - bobo demasiado simples tokenizer lê "não" como {didn, t} e "Ela é" como {ela, s} :)
hobbs

Respostas:

123

LabVIEW 51 nós, 5 estruturas, 10 diagramas

Ensinar o elefante a sapatear nunca é bonito. Ah, vou pular a contagem de caracteres.

código labVIEW

resultados

O programa flui da esquerda para a direita:

código do labVIEW explicado

Joe Zoller
fonte
10
Não vale a pena
4
O LabVIEW está muito feliz com seu nicho de controle e medição de hardware, mas realmente péssimo para manipulação de strings.
Joe Z
19
Melhor resposta de código de golfe que eu já vi. +1 por pensar fora da caixa!
Blair Holloway
1
Temos que contar os elementos para nós ... cada caixa e widget que você teve que arrastar para a tela conta.
dmckee --- ex-moderador gatinho
1
Seria possível adicionar um link para uma versão maior desses gráficos?
Svish 07/07
42

Ruby 1.9, 185 caracteres

(fortemente baseado nas outras soluções 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}]

Em vez de usar qualquer opção de linha de comando como as outras soluções, você pode simplesmente passar o nome do arquivo como argumento. (ie ruby1.9 wordfrequency.rb Alice.txt)

Como estou usando caracteres literais aqui, esta solução funciona apenas no Ruby 1.9.

Editar: ponto-e-vírgula substituído por quebras de linha para "legibilidade". : P

Edit 2: Shtééf apontou que eu esqueci o espaço à direita - consertei isso.

Edit 3: Removido o espaço à direita novamente;)

Ventero
fonte
Está faltando o espaço à direita, após cada palavra.
Stéphan Kochen
Aww atirar, desconsidere isso. Parece que o golfe acabou de ser atualizado, o espaço à direita não é mais necessário. :)
Stéphan Kochen
Não parece acomodar para 'superlongstringstring' na 2ª ou mais recente posição? (ver descrição do problema)
Nas Banov
2
Isso parece realmente sustentável.
Zombies
39

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

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

Explicação:

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

"Correto" (espero). (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 - meio 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*'| '@}/

Saída visível nos logs de revisão.

Nabb
fonte
2
Sobre GolfScript: golfscript.com/golfscript
Assaf Lavie
2
Não está correto, pois se a segunda palavra for realmente longa, ela será quebrada para a próxima linha.
Gabe
5
"dividir por zero" ... GolfScript permite isso?
JAB
35

206

shell, grep, tr, grep, tipo, uniq, tipo, cabeça, 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, apenas visto acima: sort -nr-> sort -ne depois head-> tail=> 208 :)
update2: erm, é claro que o acima é bobo, pois será revertido então. Então, 209.
update3: otimizou o regexp de exclusão -> 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 diversão, aqui está uma versão somente para perl (muito mais rápida):

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

Transacionar a solução baseada em conjunto SQL (SQL Server 2005) 1063 892 873 853 827 820 783 683 647 644 630 caracteres

Obrigado a Gabe por algumas sugestões úteis para reduzir a contagem de caracteres.

Nota: Quebras de linha adicionadas para evitar barras de rolagem, somente a última quebra de linha é necessária.

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 @

Versão legível

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 @

Resultado

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

E com a longa corda

 _______________________________________________________________ 
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| Alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| at
|_________________________| with
|_______________________| on
|______________________| all
|____________________| This
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| So
|________________| very
|________________| what
Martin Smith
fonte
12
Eu te dei um +1 porque você fez isso no T-SQL e para citar o Team America - "Você tem bolas. Eu gosto de bolas".
Tomei a liberdade de converter alguns espaços em novas linhas para torná-lo mais legível. Espero que eu não estrague tudo. Eu também reduzi um pouco mais.
Gabe
3
Esse código está gritando comigo! : O
Joey
1
Uma boa maneira de economizar é alterando 0.000para just 0e usando em -Cvez de 1.0/C. E transformar FLOATem REALsalvará um derrame também. O mais importante, porém, é que parece que você tem várias ASinstâncias que devem ser opcionais.
Gabe
1
OK, que 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

Uma melhoria no Anurag, incorporando sugestões da rfusca. Também remove argumento para classificar e alguns outros pequenos golfe.

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

Executar como:

ruby GolfedWordFrequencies.rb < Alice.txt

Edit: colocar 'puts' de volta, precisa estar lá para evitar cotações na saída.
Edit2: Arquivo Alterado-> IO
Edit3: removido / i
Edit4: Removido parênteses em torno de (f * 1.0), recontado
Edit5: Use adição de string para a primeira linha; expandir sno local.
Edit6: Feito m flutuar, removido 1.0. EDIT: Não funciona, muda comprimentos. EDIT: Não é pior do que antes
Edit7: Use STDIN.read.

archgoon
fonte
+1 - amo a parte de classificação, muito inteligente :)
Anurag
Ei, pequena otimização em comparação com a maior parte dela em primeiro lugar. :)
archgoon
Agradável! Adicionadas duas das alterações que também fiz na versão do Anurag. Barbeia-se outro 4.
Stéphan Kochen
A solução se desviou da saída original, vou tentar descobrir onde isso aconteceu.
archgoon
1
Há uma variante mais curta disso ainda mais.
Archdev #
28

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

e Teste de Direito da Zipf

Olha mamãe ... sem vars, sem mãos, .. sem cabeça

Editar 1> algumas taquigrafia 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]

Algumas explicações

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)

Resultado

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

O Mathematica não é adequado para jogar golfe, e isso é devido aos nomes longos e descritivos das funções. Funções como "RegularExpression []" ou "StringSplit []" me fazem soluçar :(.

Teste da Lei de Zipf

A lei de Zipf prevê que, para um texto em linguagem natural, o gráfico Log (Classificação) vs Log (ocorrências) segue uma relação linear .

A lei é usada no desenvolvimento de algoritmos para criptografia e compactação de dados. (Mas NÃO é o "Z" no algoritmo LZW).

Em nosso texto, podemos testá-lo com o seguinte

 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]

O resultado é (bastante linear)

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

Editar 6> (242 caracteres)

Refatorando o Regex (sem função Selecionar mais)
Eliminando 1 char char
Definição mais eficiente para a função "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]
  • Substituído fpor Transposee Slot( #1/ #2) argumentos.
  • Não precisamos de colchetes fedorentos (use em f@xvez de sempre f[x]que possível)

belisarius
fonte
9
Você acha que "RegularExpression" é ruim? Chorei quando digitei "System.Text.RegularExpressions.Regex.Split" na versão C #, até que vi o código do Objective-C: "stringWithContentsOfFile", "enumerateSubstringsInRange", "NSStringEnumerationByWords", "NSStringEnumerationByWords", "SortArrayUsingComparator" e assim por diante .
Gabe
2
@ Gabriel Obrigado ... Eu me sinto melhor agora. Em espanhol, dizemos "mal de muchos, consuelo de tontos" .. Algo como "Muitos incomodados, tolos aliviados": D
Dr. belisarius
1
O |i|é redundante no seu regex porque você já possui .|.
Gabe
1
Eu gosto do ditado espanhol. A coisa mais próxima que consigo pensar em inglês é "miséria adora companhia". Aqui está minha tentativa de tradução: "É um tolo que, quando sofre, consola-se ao pensar nos outros na mesma situação". Trabalho surpreendente na implementação do Mathematica, btw.
Dreeves
@dreeves Foolishness superar a barreira da língua facilmente ... Fico feliz em vê-lo como meu pequeno programa Mathematica, eu estou apenas começando a aprender a língua
Dr. belisarius
26

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

Não é tão curto, mas agora provavelmente correto! Observe que a versão anterior não mostrava a primeira linha das barras, não as dimensionava corretamente, baixou o arquivo em vez de obtê-lo do stdin e não incluiu toda a verbosidade C # necessária. Você poderia facilmente raspar muitos traços se o C # não precisasse de tanta porcaria extra. Talvez o Powershell pudesse fazer melhor.

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 com lendivisor embutido (o que o torna 22 vezes mais lento) no formulário abaixo (novas linhas usadas para selecionar espaços):

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
fonte
+1 para o espertinho que está baixando o arquivo em linha. :)
sarnold
1
Roube o URL curto da resposta de Matt.
indiv
2
A especificação disse que o arquivo deve ser canalizado ou passado como um argumento. Se você assumisse que args [0] continha o nome do arquivo local, poderia encurtá-lo consideravelmente usando args [0] em vez de (novo WebClient ()). DownloadString (@ " gutenberg.org/files/11/11. txt" ) -> que iria poupar cerca de 70 caracteres
thorkia
1
Aqui está uma versão substituindo a chamada WebClient por args 0, uma chamada para StreamReader e removendo alguns espaços extras. Contagem total de caracteres = 413 var a = Regex.Replace ((new StreamReader (args [0])). ReadToEnd (), "[^ a-zA-Z]", "") .ToLower (). Split ('' ) .Where (x =>! (New [] {"the", "and", "of", "to", "a", "i", "it", "in", "or", " is "}). Contém (x)). GroupBy (x => x). Selecione (g => new {w = g.Key, c = g.Count ()}). OrderByDescending (x => xc). Pule (1) .Take (22) .ToList (); var m = a.OrderByDescending (x => xc) .Primeiro (); a.ForEach (x => Console.WriteLine ("|" + nova String (' _ ', xc * (80-mwLength-4) / mc) + "|" + xw));
Thorkia
"novo StreamReader" sem "usar" está sujo. File.ReadAllText (args [0]) ou Console.In.ReadToEnd () são muito melhores. Neste último caso, você pode até remover o argumento do seu Main (). :)
Rotsor
25

Perl, 237 229 209 caracteres

(Atualizado novamente para vencer a versão Ruby com mais truques sujos de golfe, substituindo split/[^a-z/,lc-os lc=~/[a-z]+/ge eliminando um cheque de string vazio em outro local. Eles foram inspirados na versão Ruby, portanto, credite onde é devido o crédito.)

Atualização: agora com Perl 5.10! Substitua printpor saye use ~~para evitar a map. Isso deve ser chamado na linha de comando como perl -E '<one-liner>' alice.txt. Como o script inteiro está em uma linha, escrevê-lo como uma linha não deve apresentar nenhuma dificuldade :).

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

Observe que esta versão é normalizada para maiúsculas e minúsculas. Isso não reduz a solução, já que a remoção ,lc(para caixa inferior) exige que você adicione A-Zao regex dividido, portanto é uma lavagem.

Se você estiver em um sistema em que uma nova linha seja um caractere e não dois, você poderá reduzi-lo em mais dois caracteres usando uma nova linha literal no lugar de \n. No entanto, não escrevi o exemplo acima dessa maneira, pois é "mais claro" (ha!) Dessa maneira.


Aqui está uma solução perl mais correta, mas não remotamente curta o suficiente:

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

A seguir, é o mais curto possível, permanecendo relativamente legível. (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;
JSB ձոգչ
fonte
Tem alguns bugs agora; fixação e encurtamento.
JSB
4
Isso não cobre o caso quando a segunda palavra é muito maior que a primeira, certo?
Joey
1
Ambos foreach s podem ser escritos como fors. Isso é 8 caracteres abaixo. Então você tem o grep{!($_~~@s)}map{lc=~/[a-z]+/g}<>, que eu acredito que poderia ser escrito grep{!(/$_/i~~@s)}<>=~/[a-z]+/gpara diminuir mais 4. Substitua o " "com $"e você está para baixo 1 mais ...
Zaid
sort{$c{$b}-$c{$a}}...para economizar mais dois. Você também pode simplesmente passar %cem vez de keys %cpara a sortfunção e salvar mais quatro.
mob
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]

(A última quebra de linha não é necessária, mas incluída aqui para facilitar a leitura.)

(Código atual e meus arquivos de teste disponíveis no meu repositório SVN . Espero que meus casos de teste detectem os erros mais comuns (comprimento da barra, problemas com a correspondência de expressões regulares e mais alguns))

Premissas:

  • ASCII dos EUA como entrada. Provavelmente fica estranho com Unicode.
  • Pelo menos duas palavras ininterruptas no texto

História

Versão relaxada (137), já que é contada separadamente até agora, aparentemente:

($x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *)[-1..-22]|%{"|$('_'*(76*$_.Count/$x[-1].Count))| "+$_.Name}
  • não fecha a primeira barra
  • não considera o comprimento da palavra que não é a primeira palavra

Variações dos comprimentos de barra de um caractere em comparação com outras soluções são devidas ao PowerShell usar arredondamento em vez de truncamento ao converter números de ponto flutuante em números inteiros. Como a tarefa exigia apenas o comprimento proporcional da barra, isso deveria ser bom.

Comparado a outras soluções, adotei uma abordagem um pouco diferente para determinar o comprimento mais longo da barra, simplesmente testando e obtendo o maior comprimento, onde nenhuma linha tem mais de 80 caracteres.

Uma versão mais antiga explicada pode ser encontrada aqui .

Јοеу
fonte
Impressionante, parece que o Powershell é um ambiente adequado para jogar golfe. Sua abordagem considerando o comprimento da barra é exatamente o que tentei descrever (não tão brilhantemente, admito) nas especificações.
ChristopheD
1
@ChristopheD: Na minha experiência (Anarchy Golf, algumas tarefas do Project Euler e outras mais apenas por diversão), o PowerShell geralmente é apenas um pouco pior que o Ruby e geralmente está vinculado ou melhor que o Perl e o Python. Não é páreo para o GolfScript. Mas, tanto quanto eu posso ver, isso pode ser a solução mais curta que corretamente representa comprimentos bar ;-)
Joey
Aparentemente, eu estava certa. O PowerShell pode fazer melhor - muito melhor! Forneça uma versão expandida com comentários.
Gabe
Johannes: Você tentou -split("\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z]")? Funciona para mim.
Gabe
Não se esqueça de interpolar a sequência de saída: "|$('_'*($w*$_.count/$x[0].count))| $($_.name) "(ou eliminar o último espaço, pois é meio automático). E você pode usar -split("(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z])+")para economizar um pouco mais, não incluindo espaços em branco (ou use [-2..-23]).
Gabe
19

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

atualização 1: Hurrah ! É um empate com JS Bangs ' solução de . Não consigo pensar em uma maneira de reduzir mais :)

atualização 2: jogou um truque sujo de golfe. Alteradoeach para mapsalvar 1 caractere :)

atualização 3: alterada File.readpara IO.read+2. Array.group_bynão foi muito proveitoso, mudou parareduce +6. A verificação sem distinção entre maiúsculas e minúsculas não é necessária após o revestimento inferior downcaseno regex +1. A classificação em ordem decrescente é feita facilmente, negando o valor +6. Economia total +15

atualização 4: em [0]vez de.first +3. (@ Shtééf)

atualização 5: expanda a variável lno local, +1. Expandir variávels no local, +2. (@ Shtééf)

atualização 6: use adição de string em vez de interpolação para a primeira linha, +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} "}

atualização 7: passei por muita confusão para detectar a primeira iteração dentro do loop, usando variáveis ​​de instância. Tudo o que recebi é +1, embora talvez haja potencial. Preservando a versão anterior, porque acredito que essa é 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} "}

Versão legível

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

Resultado:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
Anurag
fonte
3
"P" não é um atalho para "põe"? Isso poderia raspar alguns.
Rfusca
1
Agradável. Seu uso scan, no entanto, me deu uma idéia melhor, então eu fui à frente novamente :).
JSB
2
Você precisa dimensionar as barras para que a palavra mais longa e a barra se ajustem a 80 caracteres. Como Brian sugeriu, uma longa segunda palavra interromperá seu programa.
Gabe
3
Eu me pergunto por que isso ainda está ganhando votos. A solução está incorreta (no caso geral) e as soluções Ruby bidirecionais mais curtas já estão aqui.
Joey
1
Agora, corrija-me se estiver errado, mas em vez de usar "minúscula", por que você não usa o sinalizador sem distinção entre maiúsculas e minúsculas REGEXP, que economiza de 6 a 7 bytes, não é?
st0le
19

Python 2.x, abordagem latitudinariana = 227 183 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

Permitindo liberdade na implementação, construí uma concatenação de strings que contém todas as palavras solicitadas para exclusão ( the, and, of, to, a, i, it, in, or, is) - além de também excluir as duas "palavras" infames se tdo exemplo - e introduzi gratuitamente a exclusão de an, for, he. Tentei todas as concatenações dessas palavras contra o corpus das palavras de Alice, a Bíblia do rei James e o arquivo do jargão para ver se há alguma palavra que será excluída incorretamente pela sequência. E foi assim que terminei com duas cadeias de exclusão: itheandtoforiniseandithetoforinis .

PS. emprestado de outras soluções para encurtar o código.

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

Rant

Com relação às palavras a serem ignoradas, alguém poderia pensar que essas palavras seriam retiradas da lista das palavras mais usadas em inglês. Essa lista depende do corpus de texto usado. Por uma das listas mais populares ( http://en.wikipedia.org/wiki/Most_common_words_in_English , http://www.english-for-students.com/Frequently-Used-Words.html , http: // www. sporcle.com/games/common_english_words.php ), as 10 principais palavras são:the be(am/are/is/was/were) to of and a in that have I

As 10 principais palavras do texto Alice no País das Maravilhas são the and to a of it she i you said
As 10 principais palavras do Arquivo de Jargões (v4.4.7) sãothe a of to and in is that or for

Então, a pergunta é por que orfoi incluída na lista de ignorados do problema, onde é ~ 30 em popularidade quando a palavra that(8ª mais usada) não é. etc, etc. Portanto, acredito que a lista de ignorados deve ser fornecida dinamicamente (ou pode ser omitida).

A idéia alternativa seria simplesmente pular as 10 principais palavras do resultado - o que realmente reduziria a solução (elementar - deve mostrar apenas as entradas de 11 a 32).


Python 2.x, abordagem meticulosa = 277 243 caracteres

O gráfico desenhado no código acima é simplificado (usando apenas um caractere para as barras). Se alguém quiser reproduzir exatamente o gráfico a partir da descrição do problema (o que não era necessário), este código fará isso:

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

Aceito um problema com a escolha um tanto aleatória das 10 palavras para excluir the, and, of, to, a, i, it, in, or, is para que elas sejam passadas como parâmetros de linha de comando, assim:
python WordFrequencyChart.py the and of to a i it in or is <"Alice's Adventures in Wonderland.txt"

São 213 caracteres + 30 se considerarmos a lista de ignorados "original" passada na linha de comando = 243

PS. O segundo código também faz "ajuste" para os comprimentos de todas as palavras principais, para que nenhuma delas transborde em caso de degeneração.

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|_____________________________________________________| said
|______________________________________________| alice
|_________________________________________| was
|______________________________________| that
|_______________________________| as
|____________________________| her
|__________________________| at
|__________________________| with
|_________________________| s
|_________________________| t
|_______________________| on
|_______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|___________________| not
|_________________| they
|_________________| so
Nas Banov
fonte
Solução agradável até agora, embora a palavra lista de ignorados ainda não esteja implementada e as barras sejam um pouco rudimentares no momento.
ChristopheD
@ChristopheD: estava lá, mas não havia um "guia do usuário". Acabei de adicionar texto de grupo
Nas Banov
Em relação à sua lista de idiomas e soluções: procure soluções que usem divisão ao longo \Wou \bem uma regex, porque essas provavelmente não estão de acordo com as especificações, o que significa que não serão divididas em dígitos ou _podem também não remover palavras de parada das strings tais como the_foo_or123bar. Eles podem não aparecer no texto de teste, mas a especificação é bastante clara nesse caso.
Joey
Trabalho incrível Nas, passei uma tarde tentando otimizar isso e só encontrei uma melhoria. Você pode cortá-la para baixo para 239 caracteres, removendo o sys.argvhack and usando:re.findall(r'\b(?!(?:the|and|.|of|to|i[tns]|or)\b)\w+',sys.stdin.read().lower())
intgr
12

Haskell - 366 351 344 337 333 caráteres

(Uma quebra de linha foi mainadicionada para facilitar a leitura e nenhuma quebra de linha é necessária no final da última linha.)

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

Como funciona é melhor visto lendo o argumento para interacttrás:

  • map f em minúsculas, substitui todo o resto por espaços.
  • words produz uma lista de palavras, eliminando o espaço em branco de separação.
  • filter (notElem words "the and of to a i it in or is")descarta todas as entradas com palavras proibidas.
  • group . sort classifica as palavras e agrupa as idênticas em listas.
  • map h mapeia cada lista de palavras idênticas a uma tupla do formulário (-frequency, word) .
  • take 22 . sort classifica as tuplas por frequência decrescente (a primeira entrada da tupla) e mantém apenas as 22 primeiras.
  • b mapeia tuplas para barras (veja abaixo).
  • a precede a primeira linha de sublinhados para completar a barra superior.
  • unlines une todas essas linhas com novas linhas.

A parte complicada é acertar o comprimento da barra. Eu assumi que apenas os sublinhados ||eram contados no comprimento da barra; portanto, seria uma barra de comprimento zero. A função bmapeia c xmais x, onde xa lista de histogramas. A lista inteira é passada para c, para que cada chamada de cpossa calcular o fator de escala para si mesma chamando u. Dessa maneira, evito usar matemática ou racional de ponto flutuante, cujas funções de conversão e importações consumiriam muitos caracteres.

Observe o truque de usar -frequency. Isso elimina a necessidade de reversea sortclassificação (crescente) -frequencycolocar as palavras com a maior frequência primeiro. Posteriormente, na função u, dois -frequencyvalores são multiplicados, o que cancelará a negação.

Thomas
fonte
Um trabalho muito bom (votaria positivamente, mas ficou sem votos para hoje com todas as ótimas respostas neste tópico).
ChristopheD
Isso machuca meus olhos de uma maneira que é dolorosa até pensar em descrever, mas eu aprendi muito Haskell fazendo engenharia reversa em código legível. Muito bem, senhor. :-)
Owen S.
Na verdade, é Haskell bastante idiomático ainda, embora não seja realmente eficiente. Os nomes curtos fazem com que pareça muito pior do que realmente é.
Thomas
@ Thomas: Você pode dizer isso de novo. :-)
Owen S.
1
Não é possível mover o div , na verdade! Experimente - a saída está errada. A razão é que fazer o divantes do *perde precisão.
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)}

Infelizmente, a for([k,v]in z)versão da Rhino não parece funcionar no SpiderMonkey, e readFile()é um pouco mais fácil do que usar, readline()mas subir para 1.8 nos permite usar o fechamento de funções para cortar mais algumas linhas ....

Adicionando espaço em branco para facilitar a leitura:

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

Resultado:

 _________________________________________________________________________ 
| _________________________________________________________________________ | ela
| _______________________________________________________________ | vocês
| ____________________________________________________________ | disse
| ____________________________________________________ | Alice
| ______________________________________________ | foi
| ___________________________________________ | aquele
| ___________________________________ | Como
| ________________________________ | dela
| _____________________________ | às
| _____________________________ | com
| ____________________________ | s
| ____________________________ | t
| __________________________ | em
| _________________________ | tudo
| _______________________ | isto
| ______________________ | para
| ______________________ | teve
| ______________________ | mas
| _____________________ | estar
| _____________________ | não
| ___________________ | eles
| ___________________ | tão

(versão base - não suporta larguras de barra corretamente)

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

Eu acho que minha lógica de classificação está errada, mas .. eu duno. Brainfart fixo.

Minificado (o abuso \né interpretado como ;algumas vezes):

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
fonte
Ah senhor. Eu acredito que esta é sua luva. Faça seu segundo falar com o meu.
dmckee --- ex-moderador gatinho
2
BTW-- Eu gosto do i[tns]?pouco. Muito sorrateira.
dmckee --- gatinho ex-moderador
@dmckee - bem jogado, eu não acho que eu posso bater o seu 336, desfrutar do seu merecido upvote :)
Matt
Você pode definitivamente derrotar 336 ... Há um corte de 23 caracteres disponível - .replace(/[^\w ]/g, e).split(/\s+/).map(pode ser substituído .replace(/\w+/g,e usar a mesma função que você .mapexecutou ... Também não tenho certeza se o Rhino suporta em function(a,b)b.c-a.cvez da sua função de classificação (o spidermonkey suporta), mas isso barbear {return }... b.c-a.cé um melhor tipo que a.c<b.cbtw ... Edição de uma versão Aranha na parte inferior com essas mudanças
gnarf
Mudei minha versão do SpiderMonkey para o topo, pois ela está de acordo com a restrição de largura da barra ... Também consegui cortar mais alguns caracteres na sua versão original usando um regexp de lookahead negativo para negar as palavras, permitindo uma única substituição (), e jogou alguns ifs com ?:excelente base para trabalhar!
Gnarf 03/07/19
11

Versão da CLI do PHP (450 caracteres)

Essa solução leva em consideração o último requisito que a maioria dos puristas escolheu convinientemente ignorar. Isso custou 170 caracteres!

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

Minificado:

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

Legível 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";

?>

Resultado:

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

Quando há uma palavra longa, as barras são ajustadas corretamente:

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

Python 3.1 - 245 229 caracteres

Eu acho que usar o Counter é meio trapaceiro :) Acabei de ler sobre isso cerca de uma semana atrás, então essa foi a chance perfeita de ver como ele 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 do código foi "emprestada" da solução da AKX.

sdolan
fonte
A primeira linha está faltando. E o comprimento da barra não está correto.
Joey
no seu código parece open('!')ler do stdin - em qual versão / sistema operacional está? ou você precisa nomear o arquivo '!'?
Nas Banov 03/07
Nomeie o arquivo "!" :) Desculpe, isso não estava claro, e eu deveria ter mencionado.
Sam Dolan
11

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

Algumas partes foram inspiradas pelos envios anteriores de perl / ruby, algumas idéias semelhantes foram recebidas independentemente, outras são originais. A versão mais curta também incorpora algumas coisas que eu vi / aprendi de outras apresentações.

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

Versão mais recente até 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]

Versão mais recente até 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 versão (205 caracteres) responde pelas linhas com palavras maiores que as encontradas posteriormente.

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

Implementação completa e alternativa, incluindo comportamento indicado (squishing de barras global) para o caso patológico em que a palavra secundária é popular e longa o suficiente para combinar com mais de 80 caracteres ( essa implementação é 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"}

A especificação não dizia em nenhum lugar que isso tinha que ir para STDOUT, então usei o aviso do perl () em vez da impressão - quatro caracteres salvos lá. Mapa usado em vez de foreach, mas sinto que ainda pode haver mais economia na divisão (join ()). Ainda assim, reduzi-o para 203 - pode dormir nele. Pelo menos o Perl agora está na contagem de caracteres "shell, grep, tr, grep, sort, uniq, sort, head, perl" por enquanto;)

PS: O Reddit diz "Oi";)

Atualização: join () removido em favor da atribuição e da associação implícita de conversão escalar. Até 202. Observe também que aproveitei a regra opcional "ignorar palavras de 1 letra" para cortar 2 caracteres, portanto, lembre-se de que a contagem de frequências refletirá isso.

Atualização 2: Troca de atribuição e junção implícita por matar $ / para obter o arquivo de uma só vez usando <> em primeiro lugar. Mesmo tamanho, mas mais desagradável. Trocado se (! $ Y) {} por $ y || {} &&, salvou mais 1 caractere => 201.

Atualização 3: Assumiu o controle de minúsculas antecipadamente (lc <>) movendo lc para fora do bloco do mapa - Trocou as duas expressões regulares para não usar mais a opção / i, pois não é mais necessário. Construção x? Y: z condicional explícita trocada para perlgolf tradicional || construção condicional implícita - /^...$/i?1:$x{$ } ++ para /^...$/||$x{$ } ++ Salva três caracteres! => 198, rompeu a barreira dos 200. Pode dormir em breve ... talvez.

Atualização 4: A privação do sono me deixou louco. Bem. Mais louco. Percebendo que isso só precisa analisar arquivos de texto felizes normais, desisti se atingir um nulo. Salvou dois caracteres. Substituído "length" pelo 1-char mais curto (e muito mais golfish) y /// c - você me ouviu, GolfScript ?? Estou indo para você !!! soluço

Atualização 5: Sleep dep me fez esquecer o limite de 22 linhas e o limite de linhas subseqüentes. Faça backup de 208 com aqueles manipulados. Não é tão ruim, 13 personagens para lidar com isso não é o fim do mundo. Brincou com o regex inline eval do perl, mas tendo problemas para fazê-lo funcionar e salvar caracteres ... lol. Atualizado o exemplo para corresponder à saída atual.

Atualização 6: chaves desnecessárias removidas que protegem (...), pois o doce sintático ++ permite empurrá-lo contra o felizmente. Graças à entrada de Chas. Owens (lembrando meu cérebro cansado), conseguiu a solução da classe de personagem aqui. Volte para 203.

Atualização 7: segunda parte do trabalho adicionada, implementação completa das especificações (incluindo o comportamento completo de squishing de barras para palavras longas secundárias, em vez do truncamento que a maioria das pessoas está fazendo, com base na especificação original sem o caso de exemplo patológico)

Exemplos:

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

Implementação alternativa no exemplo 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
fonte
Você pode encurtar o regex para as palavras de parada pelo colapso is|in|it|ino i[snt]?- e então não há nenhuma diferença com a regra opcional mais. (Hum, eu nunca teria pensado em dizer a um cara do Perl como fazer o Regex: D) - único problema agora: tenho que ver como posso remover três bytes da minha própria solução para ser melhor do que o Perl novamente: - |
Joey
Ok, desconsidere parte do que eu disse anteriormente. Ignorar palavras de uma letra é realmente um byte mais curto do que não fazê-lo.
Joey
Cada byte conta;) Eu considerei fazer o truque da nova linha, mas achei que era na verdade o mesmo número de bytes, mesmo que houvesse menos caracteres imprimíveis. Ainda trabalhando em ver se eu posso reduzi-lo um pouco mais :)
Syntaera
Bem, a normalização de casos me levou de volta ao 209. Não vejo o que mais eu poderia cortar. Embora o PowerShell possa ser menor que o Perl. ;-)
Joey
Não vejo onde você restringe a saída às 22 principais palavras, nem onde você garante que uma segunda palavra longa não seja quebrada.
Gabe
9

F #, 452 caracteres

Simples: obtenha uma sequência ade pares de contagem de palavras, encontre o melhor multiplicador de contagem de palavras por coluna ke imprima os 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

Exemplo (tenho contagens de frequência diferentes das suas, não sei por que):

% 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
fonte
Acontece que a minha própria solução era de fato um pouco fora (devido a uma pequena especificação diferente), as soluções correspondem agora ;-)
ChristopheD
+1 para a única implementação correta de dimensionamento de barras até agora
Rotsor
2
(@Rotsor: Ironic, considerando que a minha é a solução mais antiga.)
Brian
Aposto que você pode reduzi-lo um pouco, mesclando os estágios de divisão, mapa e filtro. Eu também esperaria que você não precisasse de tantos floats.
Gabe
As funções de aninhamento geralmente não são menores que o uso do operador de pipeline |> ?
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))

Resultado:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
AKX
fonte
1
Você pode perder a linha bm=(76.-len(W[0][0]))/W[0][1]desde que você está usando apenas bm uma vez (fazer a próxima linha U=lambda n:"_"*int(n*(76.-len(W[0][0]))/W[0][1]), raspa 5 caracteres também: por que você usar um nome de variável de 2 caracteres no golfe código ;-).?
ChristopheD
Na última linha o espaço depois de impressão não é necessário, raspa um personagem
ChristopheD
1
Não considera o caso quando a segunda palavra mais frequente é muito longa, certo?
Joey
@ChristopheD: Porque eu estava encarando esse código por um tempo demais. : P Boa captura. @ Johannes: Isso pode ser corrigido também, sim. Não tenho certeza se todas as outras implementações fizeram isso quando escrevi isso também.
AKX 05/07/10
7

* sh (+ ondulação), solução parcial

Isso está incompleto, mas, para o inferno, aqui está a frequência de palavras que conta metade do problema em 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
fonte
7

Gawk - 336 (originalmente 507) caracteres

(depois de corrigir a formatação da saída; corrigindo a coisa das contrações; aprimorando; aprimorando novamente; removendo uma etapa de classificação totalmente desnecessária; aprimorando mais uma vez; e novamente (oops, essa interrompeu a formatação); aprimore um pouco mais; aceitando o desafio de Matt, eu desesperadamente modifico muito mais; encontrei outro lugar para economizar alguns, mas devolvi dois para corrigir o erro no comprimento da barra)

Heh heh! Estou momentaneamente à frente do [Matt's JavaScript] [1] contra-desafio da solução ! ;) e [python do AKX] [2].

O problema parece exigir uma linguagem que implemente matrizes associativas nativas; portanto, é claro que eu escolhi uma com um conjunto de operadores terrivelmente deficiente. Em particular, você não pode controlar a ordem na qual o awk oferece os elementos de um mapa de hash; portanto, varro repetidamente o mapa inteiro para encontrar o item mais numeroso atualmente, imprimi-lo e excluí-lo da matriz.

É tudo terrivelmente ineficiente, com todas as golfificações que fiz, também ficaram horríveis.

Minificado:

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

quebras de linha apenas para maior clareza: elas não são necessárias e não devem ser contadas.


Resultado:

$ 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

Legível; 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
fonte
Bom trabalho, boa você incluiu uma versão recuado / comentou ;-)
ChristopheD
7

LISP comum, 670 caracteres

Eu sou um novato no LISP, e esta é uma tentativa de usar uma tabela de hash para contar (portanto, provavelmente não é o método mais 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)))))

pode ser executado, por exemplo, com cat alice.txt | clisp -C golf.lisp .

Na forma legível é

(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
fonte
você tentou instalar uma macro de leitor personalizada para reduzir algum tamanho de entrada?
Aaron
@ Aaron, na verdade, não foi trivial para mim, mesmo apenas começando esse trabalho ... :-) para a parte do golfe real, eu apenas usei variáveis ​​de uma letra e é tudo. De qualquer forma, além da verbosidade um pouco alta que é inerente ao CL para essa escala de problemas ("concatenar 'string", "setf" ou "gethash" são assassinos ... em python eles são "+", "=", "[]" ) ainda me sentia muito pior do que esperava, mesmo em um nível lógico. Em certo sentido, tenho a sensação de que o lisp está ok, mas o lisp comum é mais ou menos e isso está além do nome (reler um comentário muito injusto, pois minha experiência com CL está próxima de zero).
6502
verdade. esquema tornaria o golfe um pouco mais fácil, com o único espaço para nome. em vez de corda-de acréscimo em todo o lugar, você poderia (letrec ((uma seqüência de acréscimo) (b gethash)) ... (a "x" "yz") ...)
Aaron
6

C (828)

Parece um código ofuscado e usa glib para string, list e hash. Contagem de caracteres com wc -mdiz 828 . Não considera palavras de caractere único. Para calcular o comprimento máximo da barra, considere a palavra mais longa possível entre todas, não apenas as primeiras 22. Isso é um desvio da especificação?

Ele não lida com falhas e não libera a memória 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);}
ShinTakezou
fonte
As novas linhas contam como caracteres, mas você pode remover linhas que não sejam instruções do pré-processador. Para um golfe, eu não consideraria não liberar memória uma prática ruim.
Stéphan Kochen
ok ... coloque tudo em linha (espere macros preproc) e dê um vers sem liberar mem (e com outros dois espaços removidos ... um pouco de melhoria pode ser feita na "ofuscação", por exemplo *v=*v*(77-lw)/m, dará 929. .. mas eu acho que pode ser ok se eu não encontrar uma maneira de fazê-lo muito mais curto)
ShinTakezou
Eu acho que você pode mover-se pelo menos a int cna maindeclaração e mainé implicitamente int(como são quaisquer argumentos sem tipo, afaik): main(c){...}. Você provavelmente também poderia apenas escrever em 0vez de NULL.
Joey
fazê-lo ... é claro, acionará algum aviso com o sinalizador -Wallou -std=c99... mas suponho que isso não faz sentido para um código-golfe, certo?
ShinTakezou
uff, desculpe-me pelas edições de curto espaço de tempo, ... eu deveria mudar Without freeing memory stuff, it reaches 866 (removed some other unuseful space)para outra coisa para não pensar nas pessoas que a diferença com a versão de memória livre é tudo isso: agora a versão sem memória livre tem muito mais "melhorias".
ShinTakezou
6

Perl, 185 caracteres

200 (ligeiramente quebrados) 199 197 195 193 187 185 caracteres. As últimas duas novas linhas são significativas. Em conformidade com as especificações.

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

A primeira linha carrega a contagem de palavras válidas %X.

A segunda linha calcula o fator de escala mínimo para que todas as linhas de saída tenham <= 80 caracteres.

A terceira linha (contém dois caracteres de nova linha) produz a saída.

mob
fonte
Isso não removerá palavras de parada de cadeias de caracteres como "foo_the_bar". Comprimento da linha também é um muito longo (re-ler a especificação: "bar + espaço + palavra + espaço <= 80 caracteres")
Joey
5

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

  • Atualizações antes do primeiro 742 : regex aprimorado, tipos parametrizados supérfluos removidos, espaço em branco supérfluo removido.

  • Atualização 742> 744 chars : corrigido o hack de comprimento fixo. Depende apenas da 1ª palavra, não de outras palavras (ainda). Foram encontrados vários locais para encurtar o código ( \\sno regex substituído por e ArrayListsubstituído por Vector). Agora estou procurando uma maneira curta de remover a dependência e leitura do Commons IO do stdin.

  • Atualização 744> 752 caracteres : removi a dependência de bens comuns. Agora ele lê de stdin. Cole o texto em stdin e pressione Ctrl+Zpara obter o resultado.

  • Atualize 752> 742 caracteres : removi publice um espaço, tornei o nome da classe 1 char em vez de 2 e agora está ignorando palavras de uma letra.

  • Atualização 742> 714 caracteres : atualizado de acordo com os comentários de Carl: a atribuição redundante removida (742> 730), substituída m.containsKey(k)por m.get(k)!=null(730> 728), introduziu a subcadeia de caracteres da linha (728> 714).

  • Atualização 714> 680 caracteres : atualizado de acordo com os comentários do Rotsor: cálculo do tamanho da barra aprimorado para remover vazamentos desnecessários e aprimorado split()para remover desnecessários 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);}}

Versão mais legível:

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

Resultado:

 _________________________________________________________________________
| _________________________________________________________________________ | ela
| _______________________________________________________________ | vocês
| ____________________________________________________________ | disse
| _____________________________________________________ | Alice
| _______________________________________________ | foi
| ___________________________________________ | aquele
| ____________________________________ | Como
| ________________________________ | dela
| _____________________________ | com
| _____________________________ | às
| __________________________ | em
| __________________________ | tudo
| _______________________ | isto
| _______________________ | para
| _______________________ | teve
| _______________________ | mas
| ______________________ | estar
| _____________________ | não
| ____________________ | eles
| ____________________ | tão
| ___________________ | muito
| __________________ | o que

É péssimo que o Java não tenha String#join()e fechamentos (ainda).

Editar por Rotsor:

Fiz várias alterações na sua solução:

  • Lista substituída por uma string []
  • Reutilizei o argumento 'args' em vez de declarar minha própria matriz String. Também o usou como argumento para .ToArray ()
  • StringBuffer substituído por uma String (sim, sim, desempenho terrível)
  • Classificação Java substituída por uma classificação de seleção com interrupção antecipada (somente os 22 primeiros elementos precisam ser encontrados)
  • Agregou alguma declaração int em uma única instrução
  • Implementou o algoritmo de não trapacear, encontrando a linha de saída mais limitadora. Implementado sem FP.
  • Corrigido o problema do travamento do programa quando havia menos de 22 palavras distintas no texto
  • Implementou um novo algoritmo de entrada de leitura, que é rápido e possui apenas 9 caracteres a mais que o lento.

O código condensado tem 688 711 684 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=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);}}}

A versão 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);}}}

Versão mais legível:

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

A versão sem melhorias de comportamento tem 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
fonte
Você não poderia simplesmente usar o nome completo para, em IOUtilsvez de importá-lo? Tanto quanto posso ver, você está usando apenas uma vez.
Joey
5
Você meio que trapaceou ao assumir que a barra mais longa terá exatamente 75 caracteres. Você precisa garantir que nenhuma barra + palavra tenha mais de 80 caracteres.
Gabe
Você está perdendo um espaço após a palavra. ;)
st0le
Enquanto reduzia minha resposta , esperava vencer a finalização de BalusC. Eu ainda tenho 200 caracteres, ugh! Gostaria de saber quanto tempo isso seria sem a premissa de Commons IO e 75 char.
Jonathon Faust
1
Parece que você pode raspar alguns caracteres criando buma String em vez de um StringBuffer. Mas não quero pensar em qual seria o desempenho (especialmente porque você está adicionando um personagem de cada vez).
Michael Myers
4

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

incluindo ajuste de palavras longas. Idéias emprestadas de outras soluções.

Agora como um 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)

Correr com

scala -howtorun:script a.scala alice.txt

Aliás, a edição de 314 a 311 caracteres na verdade remove apenas 1 caractere. Alguém entendeu errado a contagem antes (Windows CRs?).

mkneissl
fonte
4

Clojure 282 strict

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

Um pouco mais legível:

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

Scala, 368 caracteres

Primeiro, uma versão legível em 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)
    })
  }
}

A saída do console fica assim:

$ 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 fazer uma redução agressiva e reduzi-la 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))}}

A sessão do console fica assim:

$ 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

Tenho certeza de que um especialista em Scala poderia se sair ainda melhor.

Atualização: Nos comentários, Thomas deu uma versão ainda mais curta, com 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}}

De maneira legível, com 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
fonte
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
Claro, o sempre útil para a compreensão! Agradável!
Pr1001
3

Java - 896 caracteres

931 caracteres

1233 caracteres tornados ilegíveis

Chars de 1977 "não compactados"


Atualização: Reduzi agressivamente a contagem de caracteres. Omite palavras de uma letra por especificação atualizada.

Eu invejo muito C # e 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)+" ");}}}

"Legível":

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

Saída de Alice:

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

Produção de Dom Quixote (também 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
fonte
8
Totalmente carpa, não há realmente nenhuma maneira de torná-lo mais curto em Java? Espero que vocês são pagos pelo número de caracteres e não pela funcionalidade :-)
Nas Banov