Построить ASCII-диаграмму наиболее часто используемых слов в данном тексте

Задача:

Создайте диаграмму ASCII наиболее часто используемых слов в данном тексте.

Правила:

  • Принимать a-z и a-z (буквенные символы) только как часть слова.
  • Игнорировать корпус (She == She для наших целей).
  • Игнорируйте следующие слова (довольно суровые, я знаю): the, and, of, to, a, i, it, in, or, is
  • Уточнение: учитывая don't: это было бы принято как 2 разных слова в диапазонах a-z и a-z: (don и t).

  • Необязательно (слишком поздно, чтобы формально изменить спецификации сейчас) может выбрать все однобуквенные слова (это может потенциально для сокращения списка игнорирования тоже).

Разберите заданный text (прочитайте файл, указанный с помощью аргументов командной строки или подключенный к сети, предположим us-ascii) и создайте нам word frequency chart со следующими характеристиками:

  • Отобразите диаграмму (см. также пример ниже) для 22 наиболее распространенных слов (упорядоченных по нисходящей частоте).
  • Строка width представляет количество вхождений (частоты) слова (пропорционально). Добавьте одно место и напечатайте слово.
  • Убедитесь, что эти полосы (плюс пространство пространства-слова) всегда соответствуют: bar + [space] + word + [space] должны быть всегда <= 80 символов (убедитесь, что вы учитываете возможные разница между строками и длиной слова: например: второе наиболее распространенное слово может быть намного длиннее, чем первое, но не так сильно различающееся по частоте). Увеличьте ширину штриха в пределах этих ограничений и соответствующим образом нарисуйте полосы (в соответствии с представленными частотами).

Пример:

Текст примера можно найти здесь (Alice Adventures in Wonderland, Льюис Кэрролл).

В этом конкретном тексте будет приведена следующая диаграмма:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|____________________________________________________| alice 
|______________________________________________| was 
|__________________________________________| that 
|___________________________________| as 
|_______________________________| her 
|____________________________| with 
|____________________________| at 
|___________________________| s 
|___________________________| t 
|_________________________| on 
|_________________________| all 
|______________________| this 
|______________________| for 
|______________________| had 
|_____________________| but 
|____________________| be 
|____________________| not 
|___________________| they 
|__________________| so 


Для вашей информации: это частоты, на которых построена вышеприведенная диаграмма:

[('she', 553), ('you', 481), ('said', 462), ('alice', 403), ('was', 358), ('that
', 330), ('as', 274), ('her', 248), ('with', 227), ('at', 227), ('s', 219), ('t'
, 218), ('on', 204), ('all', 200), ('this', 181), ('for', 179), ('had', 178), ('
but', 175), ('be', 167), ('not', 166), ('they', 155), ('so', 152)]

Второй пример (чтобы проверить, была ли реализована полная спецификация): Замените каждое событие you в связанном файле Alice in Wonderland с помощью superlongstringstring:

 ________________________________________________________________
|________________________________________________________________| she 
|_______________________________________________________| superlongstringstring 
|_____________________________________________________| said 
|______________________________________________| alice 
|________________________________________| was 
|_____________________________________| that 
|______________________________| as 
|___________________________| her 
|_________________________| with 
|_________________________| at 
|________________________| s 
|________________________| t 
|______________________| on 
|_____________________| all 
|___________________| this 
|___________________| for 
|___________________| had 
|__________________| but 
|_________________| be 
|_________________| not 
|________________| they 
|________________| so 

Победитель:

Кратчайшее решение (по количеству символов, по языку). Получайте удовольствие!


Изменить: таблица, обобщающая результаты до сих пор (2012-02-15) (первоначально добавленный пользователем Нас Банов):

Language          Relaxed  Strict
=========         =======  ======
GolfScript          130     143
Perl                        185
Windows PowerShell  148     199
Mathematica                 199
Ruby                185     205
Unix Toolchain      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

Цифры представляют длину кратчайшего решения на определенном языке. "Строгий" относится к решению, полностью реализующему спецификацию (рисует строки |____|, закрывает первый балл сверху линией ____, учитывает возможность длинных слов с высокой частотой и т.д.). "Relaxed" означает, что некоторые свободы были сокращены до решения.

В комплект включены только решения длиной менее 500 символов. Список языков сортируется по длине "строгого" решения. "Unix Toolchain" используется для обозначения различных решений, которые используют традиционную оболочку * nix плюс набор инструментов (например, grep, tr, sort, uniq, head, perl, awk).

Ответы

Ответ 1

LabVIEW 51 узел, 5 структур, 10 диаграмм

Преподавание слона, чтобы танцевать, никогда не бывает красивым. Я, ах, пропущу количество символов.

labVIEW code

results

Программа перемещается слева направо:

объясняется код labVIEW

Ответ 2

Ruby 1.9, 185 символов

(в значительной степени основанный на других решениях 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}]

Вместо использования каких-либо переключателей командной строки, таких как другие решения, вы можете просто передать имя файла в качестве аргумента. (т.е. ruby1.9 wordfrequency.rb Alice.txt)

Поскольку я использую символьные литералы здесь, это решение работает только в Ruby 1.9.

Изменить: Заменены точки с запятой разрывами строк для "удобочитаемости".: P

Отредактируйте 2: Shtééf указал, что я забыл конечное пространство - исправил это.

Правка 3: снова удалено конечное пространство;)

Ответ 3

GolfScript, 177 175 173 167 164 163 144 131 130 символов

Медленно - 3 минуты для текста примера (130)

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

Пояснение:

{           #loop through all characters
 32|.       #convert to uppercase and duplicate
 123%97<    #determine if is a letter
 [email protected]       #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
([email protected]         #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
}/

"Правильно" (надеюсь). (143)

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

Менее медленный - полминуты. (162)

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

Выход отображается в журналах изменений.

Ответ 4

206

shell, grep, tr, grep, sort, uniq, sort, head, perl

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

hm, как видно выше: sort -nrsort -n, а затем headtail = > 208:)
update2: erm, конечно, это глупо, так как тогда оно будет отменено. Итак, 209.
update3: оптимизировано исключение regexp → 206

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



для удовольствия, здесь версия perl-only (намного быстрее):

~ % 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)."| $_"[email protected]'
~ % # usage:
~ % sh pgolf < 11.txt

Ответ 5

Решение на основе набора Transact SQL (SQL Server 2005) 1063 892 873 853 827 820 783 683 647 644 630 символов

Спасибо Gabe за полезные советы, чтобы уменьшить количество символов.

NB: добавлены разрывы строк, чтобы избежать полос прокрутки, требуется только последний разрыв строки.

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 @[email protected]+' 
|'+REPLICATE('_',-C*@F)+'| '+W FROM # ORDER BY C PRINT @

Считываемая версия

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 guaranteed but it works on my machine :-) */
SELECT @F=MIN(($76-LEN(W))/-C),
       @ =' '      +REPLICATE('_',-MIN(C)*@F)+' '
FROM   #

SELECT @[email protected]+' 
|'+REPLICATE('_',-C*@F)+'| '+W
             FROM     #
             ORDER BY C

PRINT @

Выход

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

И с длинной строкой

 _______________________________________________________________ 
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| Alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| at
|_________________________| with
|_______________________| on
|______________________| all
|____________________| This
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| So
|________________| very
|________________| what

Ответ 6

Ruby 207 213 211 210 207 203 201 200 символов

Улучшение Anurag, включающее предложение от rfusca. Также удаляет аргумент для сортировки и несколько других второстепенных игр.

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

Выполнить как:

ruby GolfedWordFrequencies.rb < Alice.txt

Изменить: поставить 'puts' обратно, нужно быть там, чтобы избежать наличия кавычек в выводе.
Edit2: Измененный файл- > IO
Edit3: удален /i
Edit4: Удаленные круглые скобки вокруг (f * 1.0), пересчитанные
Edit5: используйте добавление строк для первой строки; разверните s на месте.
Edit6: Сделано m float, удалено 1.0. EDIT: не работает, изменяется длина. EDIT: не хуже, чем раньше Edit7: используйте STDIN.read.

Ответ 7

Математика ( 297 284 248 244 242 199 символов) Чистая функциональная

и Zipf Law Testing

Посмотрите, мама... нет варов, нет рук, нет головы

Изменить 1 > определенные сокращения (284 символа)

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]

Некоторые объяснения

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)

Выход

alt text http://i49.tinypic.com/2n8mrer.jpg

Mathematica не очень подходит для игры в гольф, и это происходит только из-за длинных описательных имен функций. Такие функции, как "RegularExpression []" или "StringSplit []", просто заставляют меня рыдать: (.

Zipf Law Testing

Закон Zipf предсказывает, что для текста на естественном языке Журнал (ранг) vs Журнал (вхождения) Участок следует за линейной.

Закон используется при разработке алгоритмов криптографии и сжатия данных. (Но это НЕ "Z" в алгоритме LZW).

В нашем тексте мы можем протестировать его с помощью следующих

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

Результат (довольно хорошо линейный)

alt text http://i46.tinypic.com/33fcmdk.jpg

Изменить 6 > (242 символа)

Рефакторинг регулярного выражения (больше нет функции выбора)
Отбрасывание 1 char слов
Более эффективное определение функции "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]

Изменить 7 → 199 символов

BarChart[#2, BarOrigin->Left, ChartLabels->Placed[#1, After], Axes->None]&@@ 
  [email protected][SortBy[[email protected][[email protected]@i, 
    [email protected]"(\\W|\\b(.|the|and|of|to|i[tns]|or)\\b)+"],Last], -22]
  • Заменили f аргументами Transpose и Slot (#1/#2).
  • Нам не нужны никакие скобки stinkin (используйте [email protected] вместо f[x], где это возможно)

Ответ 8

С# - 510 451 436 446 434 426 422 символа (minified)

Не так коротка, но теперь, наверное, правильно! Обратите внимание, что предыдущая версия не отображала первую строку столбцов, не правильно масштабировала бары, загружала файл, а не получала его из stdin, и не включала в себя всю требуемую детальность С#. Вы могли бы легко побрить много ударов, если бы С# не требовалось столько лишнего дерьма. Возможно, Powershell может сделать лучше.

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 символа с lendivisor inlined (что делает его в 22 раза медленнее) в форме ниже (новые строки, используемые для выбранных пробелов):

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

Ответ 9

Perl, 237 229 209 символов

(Обновлен снова, чтобы обыграть версию Ruby с более грязными трюками для гольфа, заменив split/[^a-z/,lc на lc=~/[a-z]+/g и устранив проверку пустой строки в другом месте. Они были вдохновлены версией Ruby, поэтому кредит, из-за.)

Обновление: теперь с Perl 5.10! Замените print на say и используйте ~~, чтобы избежать map. Это нужно вызвать в командной строке как perl -E '<one-liner>' alice.txt. Поскольку весь script находится на одной строке, запись его как однострочного слоя не должна представлять никаких трудностей:).

 @s=qw/the and of to a i it in or is/;$c{$_}++foreach grep{!([email protected])}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)."| $_ "[email protected][0..21];

Обратите внимание, что эта версия нормализуется для случая. Это не сокращает решение, так как удаление ,lc (для нижней части корпуса) требует добавления A-Z в разделяемое регулярное выражение, поэтому это стирка.

Если вы находитесь в системе, где символом новой строки является один символ, а не два, вы можете сократить это на два других символа, используя вместо символа \n литеральную новую строку. Тем не менее, я так не написал вышеприведенный образец, так как он "более ясный" (ха!) Таким образом.


Вот, в основном, правильный, но не достаточно короткий, perl-решение:

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

Ниже приведено краткое, которое можно получить, оставаясь относительно читаемым. (392 символа).

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

Ответ 10

Windows PowerShell, 199 символов

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

(Последний разрыв строки не нужен, но включен здесь для удобочитаемости.)

(Текущий код и мои тестовые файлы доступны в моем репозитории SVN. Надеюсь, что в моих тестовых случаях обнаружены наиболее распространенные ошибки (длина бара, проблемы с совпадением регулярных выражений и несколькими другими))

Предположения:

  • US ASCII в качестве входного. Вероятно, это странно с Unicode.
  • В тексте по крайней мере два слова без пробела

История

Расслабленная версия (137), так как теперь она подсчитывается отдельно, по-видимому:

($x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *)[-1..-22]|%{"|$('_'*(76*$_.Count/$x[-1].Count))| "+$_.Name}
  • не закрывает первый бар
  • не учитывает длину слова не первого слова

Вариации длин бара одного символа по сравнению с другими решениями обусловлены использованием PowerShell с использованием округления вместо усечения при преобразовании чисел с плавающей запятой в целые числа. Поскольку задача требует только пропорциональной длины бара, это должно быть хорошо.

По сравнению с другими решениями я принял несколько иной подход при определении самой длинной длины бара, просто попробовав и получив самую высокую такую ​​длину, где длина строки не превышает 80 символов.

Более старую версию можно найти здесь.

Ответ 11

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

update 1: Ура! Это связь с JS Bangs . Не могу придумать способ срубить больше:)

update 2: сыграл грязный трюк в гольф. Изменено each до map, чтобы сохранить 1 символ:)

update 3: Изменено File.read до IO.read +2. Array.group_by был не очень плодотворным, его заменили на reduce +6. Нечувствительность к регистру не нужна после нижнего корпуса с downcase в регулярном выражении +1. Сортировка в порядке убывания легко выполняется путем отрицания значения +6. Общая экономия +15

обновить 4: [0], а не .first, +3. (@Shtééf)

update 5: Развернуть переменную l на месте, +1. Разверните переменную s на месте, +2. (@Shtééf)

update 6: используйте добавление строки вместо интерполяции для первой строки +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} "}

update 7: я прошел через множество хоопл, чтобы обнаружить первую итерацию внутри цикла, используя переменные экземпляра. Все, что у меня есть, +1, хотя, возможно, есть потенциал. Сохраняя предыдущую версию, потому что я считаю, что это черная магия. (@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} "}

Считываемая версия

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

Для использования:

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

Вывод:

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

Ответ 12

Python 2.x, latitudinarian approach = 227 183 символа

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

Разрешая свободу в реализации, я построил конкатенацию строк, содержащую все слова, запрошенные для исключения (the, and, of, to, a, i, it, in, or, is), плюс он также исключает два позорных слова "s и t из примера - и я бросил бесплатно исключение для an, for, he. Я пробовал все сочетания этих слов против тела слов от Алисы, Библии короля Иакова и файла жаргона, чтобы узнать, есть ли какие-либо слова, которые будут неправильно исключены строкой. И вот как я закончил с двумя строками исключения: itheandtoforinis и andithetoforinis.

PS. заимствованы из других решений, чтобы сократить код.

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

Рант

Что касается слов, которые нужно игнорировать, можно подумать, что они будут взяты из списка наиболее часто используемых слов на английском языке. Этот список зависит от текстового корпуса. В одном из самых популярных списков (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), верхние 10 слов: the be(am/are/is/was/were) to of and a in that have I

Топ-10 слов из текста Алисы в Стране Чудес: the and to a of it she i you said
Топ-10 слов из файла Jargon (v4.4.7) - the a of to and in is that or for

Итак, вопрос в том, почему or был включен в список игнорирования проблемы, где он ~ 30-е место по популярности, когда слово that (8-е место наиболее часто используется). и т.д. Поэтому я считаю, что список игнорирования должен предоставляться динамически (или может быть опущен).

Альтернативной идеей было бы просто пропустить первые 10 слов из результата, что фактически сократило бы решение (элементарное - должно отображать только 11-332-ю записи).


Python 2.x, пунктуальный подход = 277 243 символа

График, нарисованный в приведенном выше коде, упрощается (используя только один символ для баров). Если вы хотите точно воспроизвести диаграмму из описания проблемы (что не требовалось), этот код сделает это:

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

Я беру проблему с несколько случайным выбором из 10 слов, чтобы исключить the, and, of, to, a, i, it, in, or, is, чтобы они передавались как параметры командной строки, например:
python WordFrequencyChart.py the and of to a i it in or is <"Alice Adventures in Wonderland.txt"

Это 213 символов + 30, если мы учитываем "исходный" список игнорирования, переданный по командной строке = 243

PS. Второй код также выполняет "настройку" для длин всех верхних слов, поэтому ни один из них не будет переполняться в вырожденном случае.

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|_____________________________________________________| said
|______________________________________________| alice
|_________________________________________| was
|______________________________________| that
|_______________________________| as
|____________________________| her
|__________________________| at
|__________________________| with
|_________________________| s
|_________________________| t
|_______________________| on
|_______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|___________________| not
|_________________| they
|_________________| so

Ответ 13

Haskell - 366 351 344 337 333 символа

(Один разрыв строки в main добавлен для удобочитаемости, и в конце последней строки не требуется разрыв строки.)

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

Как это работает, лучше всего увидеть, прочитав аргумент interact назад:

  • map f помещает буквы в алфавитном порядке, заменяет все остальное пробелами.
  • words создает список слов, отбрасывая разделительные пробелы.
  • filter ( notElem words "the and of to a i it in or is") отбрасывает все записи с запрещенными словами.
  • group . sort сортирует слова и группирует их в списки.
  • map h отображает каждый список одинаковых слов в кортеж формы (-frequency, word).
  • take 22 . sort сортирует кортежи по нисходящей частоте (первая запись кортежа) и сохраняет только первые 22 кортежа.
  • b отображает кортежи в бары (см. ниже).
  • a добавляет первую строку подчеркивания, чтобы завершить верхнюю панель.
  • unlines объединяет все эти строки вместе с символами новой строки.

Трудный бит - это правильная длина бара. Я предположил, что только подчеркивания подсчитываются по длине бара, поэтому || будет штрихом нулевой длины. Функция b отображает c x над x, где x - список гистограмм. Весь список передается в c, так что каждый вызов c может вычислять масштабный коэффициент для себя, вызывая u. Таким образом, я избегаю использования математики или рациональных чисел с плавающей запятой, функции конверсии и импорта которых будут содержать много символов.

Обратите внимание на трюк использования -frequency. Это устраняет необходимость reverse sort, так как сортировка (восходящая) -frequency сначала помещает слова с наибольшей частотой. Позже, в функции u, умножаются два значения -frequency, которые отменяют отрицание.

Ответ 14

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

К сожалению, for([k,v]in z) из версии Rhino, похоже, не хочет работать в SpiderMonkey, а readFile() немного проще, чем при использовании readline(), но переход до 1,8 позволяет нам использовать закрытие функций для вырезания еще несколько строк....

Добавление пробелов для чтения:

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

Использование js golf.js < input.txt

Вывод:

 _________________________________________________________________________ 
|_________________________________________________________________________| she
|_______________________________________________________________| you
|____________________________________________________________| said
|____________________________________________________| alice
|______________________________________________| was
|___________________________________________| that
|___________________________________| as
|________________________________| her
|_____________________________| at
|_____________________________| with
|____________________________| s
|____________________________| t
|__________________________| on
|_________________________| all
|_______________________| this
|______________________| for
|______________________| had
|______________________| but
|_____________________| be
|_____________________| not
|___________________| they
|___________________| so

(базовая версия - неправильно обрабатывает ширину столбца)

JavaScript (Rhino) - 405 395 387 377 368 343 304 символов

Я думаю, что моя логика сортировки отключена, но.. я duno. Brainfart исправлена.

Minified (злоупотребление \n иногда используется как ;):

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

Ответ 15

perl, 205 191 189 символов /205 символов (полностью реализовано)

Некоторые части были вдохновлены более ранними представлениями perl/ruby, пара подобных идей была получена независимо, другие оригинальны. Более короткая версия также включает в себя некоторые вещи, которые я видел/узнал из других материалов.

Оригинал:

$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 [email protected][0..21];

Последняя версия до 191 символ:

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

Последняя версия до 189 символов:

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

В этой версии (205 char) учитываются строки со словами дольше, чем то, что будет найдено позже.

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

Ответ 16

Python 3.1 - 245 229 charaters

Я предполагаю, что использование Counter - это отвращение:) Я только что прочитал об этом неделю назад, так что это был прекрасный шанс чтобы увидеть, как это работает.

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

Распечатывает:

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

Некоторые из кода были "заимствованы" из решения AKX.

Ответ 17

Версия CLI для PHP (450 символов)

Это решение учитывает последнее требование, которое большинство пуристов выбрали для удобства. Это стоило 170 символов!

Использование: php.exe <this.php> <file.txt>

уменьшенная:

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

Чтение человеком:

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

?>

Вывод:

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

Когда есть длинное слово, бары настраиваются правильно:

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

Ответ 18

Perl: 203 202 201 198 195 208 203/231 символов

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

Альтернативная полная реализация, включающая указанное поведение (глобальный барьер) для патологического случая, в котором вторичное слово является популярным и достаточно длинным, чтобы объединить более 80 символов (эта реализация составляет 231 символ):

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

В спецификации не указано нигде, что это должно было идти в STDOUT, поэтому я использовал perl warn() вместо print - там было сохранено четыре символа. Используемая карта вместо foreach, но я чувствую, что все еще можно сэкономить на сплите (join()). Тем не менее, добрался до 203 года - мог бы спать на нем. По крайней мере, Perl теперь находится под заголовками "shell, grep, tr, grep, sort, uniq, sort, head, perl" char;)

PS: Reddit говорит "Привет";)

Обновление: Удалено join() в пользу назначения и неявное скалярное преобразование. До 202. Также обратите внимание, что я воспользовался необязательным правилом "игнорировать однобуквенные слова", чтобы скрыть два символа, поэтому помните, что частота будет отражать это.

Обновление 2: Помененное назначение и неявное объединение для убийства $/, чтобы получить файл в одном gulp, используя < > в первую очередь. Такой же размер, но более неприятный. Выровнено, если (! $Y) {} для $y || {} & &, сохранено еще 1 char = > 201.

Обновление 3: Взял управление ранним ранжированием (lc < > ), перемещая lc из блока карты. Поменял оба регулярных выражения, чтобы больше не использовать параметр /i, поскольку он больше не нужен. Обменивается явным условным x? Y: z конструкцией для традиционного перлгольфа || неявная условная конструкция -/^...$/i?1:$x{$}++ для /^...$/||$x{$}++ Сохранено три символа! = > 198, сломал барьер 200. Может скоро спать... возможно.

Обновление 4: лишение сна сделало меня сумасшедшим. Что ж. Более сумасшедший. Полагая, что это только должно разбирать нормальные счастливые текстовые файлы, я заставил его отказаться, если он ударил нуль. Сохранено два символа. Заменена "длина" с 1- char короче (и гораздо больше гольфистов) y///c - вы меня слышите, GolfScript?? Я иду за тобой!!! рыдать

Обновление 5: Sleep dep заставил меня забыть о пределе 22row и последующем лимитировании. Резервное копирование до 208 с обработанными. Не так уж плохо, 13 символов для его обработки - это не конец света. Играется с регулярным выражением perl regex inline eval, но у него проблемы с его работой и сохранением символов... lol. Обновлен пример для соответствия текущему результату.

Обновление 6: Удалены ненужные фигурные скобки, защищающие (...), поскольку синтаксическая конфета ++ позволяет с уверенностью отталкивать ее. Благодаря вкладу Chas. Оуэнс (напоминая мой усталый мозг), получил решение класса я [tns]. Вернуться к 203.

Обновление 7: добавлена ​​вторая часть работы, полная реализация спецификаций (в том числе полное поведение штрих-кода для вторичных длинных слов вместо усечения, которое делает большинство людей, на основе оригинальной спецификации без случая патологического примера)

<сильные > Примеры:

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

Альтернативная реализация в случае патологического случая:

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| with
|_________________________| at
|_______________________| on
|______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| so
|________________| very
|________________| what

Ответ 19

F #, 452 символа

Strightforward: получите последовательность a пар слов-слов, найдите лучший множитель слов-счет-столбцов k, затем распечатайте результаты.

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

Пример (у меня разные частоты, чем у вас, не знаю почему):

% 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

Ответ 20

Python 2.6, 347 символов

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

Вывод:

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

Ответ 21

Gawk - 336 (изначально 507) символов

(после исправления выходного форматирования, исправления сундуков, настройки, повторной настройки, удаления полностью ненужного шага сортировки, повторной настройки, и снова (если это сломало форматирование), еще немного подкорректируйте, Я отчаянно подстроил так, нашел другое место, чтобы сохранить несколько, но дал два назад, чтобы исправить ошибку длины бара)

Хе-хе! Я на мгновение опередил решение [Matt JavaScript] [1] решение counter!;) и [AKX python] [2].

Проблема, похоже, вызывает язык, который реализует собственные ассоциативные массивы, поэтому, конечно, я выбрал один из них с ужасно дефицитным набором операторов на них. В частности, вы не можете управлять порядком, в котором awk предлагает элементы хэш-карты, поэтому я неоднократно просматриваю всю карту, чтобы найти наиболее часто используемый элемент, распечатать его и удалить из массива.

Все это ужасно неэффективно, и все поля для гольфа, которые я сделал, тоже были ужасными.

уменьшенная:

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

разрывы строк только для ясности: они не нужны и не должны учитываться.


Вывод:

$ 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

Читаемые; 633 символа (изначально 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]
    }
}

Ответ 22

* sh (+ curl), частичное решение

Это неполное, но, черт возьми, здесь слово-частота подсчитывает половину проблемы в 192 байтах:

curl -s http://www.gutenberg.org/files/11/11.txt|sed -e '[email protected][^a-z]@\[email protected]'|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

Ответ 23

Общие LISP, 670 символов

Я новичок LISP, и это попытка использовать хеш-таблицу для подсчета (возможно, это не самый компактный метод).

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

может выполняться, например, с помощью cat alice.txt | clisp -C golf.lisp.

В читаемой форме

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

Ответ 24

C (828)

Он выглядит как обфусканный код и использует glib для строки, списка и хэша. Char count с wc -m говорит 828. Он не учитывает одиночные слова char. Чтобы вычислить максимальную длину бара, он рассматривает самое длинное слово среди всех, а не только первое 22. Является ли это отклонением от spec?

Он не обрабатывает сбои и не освобождает используемую память.

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

Ответ 25

Perl, 185 char

200 (слегка сломан) <Удаp > 199удаp > <Удаp > 197удаp > <Удаp > 195удаp > <Удаp > 193удаp > <Удаp > 187удаp > 185 символов. Последние две строки новой строки значительны. Соответствует спецификации.

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

Первая строка загружает количество допустимых слов в %X.

Вторая строка вычисляет минимальный коэффициент масштабирования, так что все выходные строки будут <= 80 символов.

Третья строка (содержит два символа новой строки) выводит результат.

Ответ 26

Java - 886 865 756 744 742 744 752 742 714 680 символов

  • Обновления до первого 742: улучшено регулярное выражение, удалены избыточные параметризованные типы, удалены лишние пробелы.

  • Обновление 742 > 744 символов: исправлен взлом фиксированной длины. Это зависит только от 1-го слова, а не от других слов (пока). Нашел несколько мест, чтобы сократить код (\\s в регулярном выражении заменен на и ArrayList заменен на Vector). Я сейчас ищу короткий способ удалить зависимость IO от Commons и чтение из stdin.

  • Обновление 744 > 752 символов. Я удалил зависимость от сообщества. Теперь он читается из stdin. Вставьте текст в stdin и нажмите Ctrl+Z, чтобы получить результат.

  • Обновление 752 > 742 символов. Я удалил public и пробел, сделав имя класса 1 char вместо 2, и теперь он игнорирует однобуквенные слова.

  • Обновление 742 > 714 символов: обновлено в соответствии с комментариями Carl: удаленное резервирование (742 > 730), заменено m.containsKey(k) на m.get(k)!=null (730 > 728), введено подстрока линии (728 > 714).

  • Обновление 714 > 680 символов: обновлено в соответствии с комментариями Rotsor: улучшенный расчет размера бара, чтобы удалить ненужное литье и улучшить split(), чтобы удалить ненужный 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);}}

Более читаемая версия:

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

Вывод:

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

Это довольно отстой, что Java не имеет String#join() и закрывает (пока).

Редактировать Rotsor:

Я сделал несколько изменений в вашем решении:

  • Замененный список со строкой []
  • Повторное использование аргумента args вместо объявления моего собственного массива String. Также используется в качестве аргумента для .ToArray()
  • Заменил StringBuffer на строку (да, да, ужасная производительность)
  • Замененная сортировка по Java с сортировкой сортировки с ранним завершением (нужно найти только первые 22 элемента)
  • Сгенерировано некоторое объявление int в один оператор
  • Реализован алгоритм без мошенничества, который находит наиболее ограничительную линию вывода. Реализовано без FP.
  • Исправлена ​​проблема с сбоем программы, когда в тексте было меньше 22 различных слов.
  • Реализован новый алгоритм чтения ввода, который является быстрым и всего 9 символов длиннее медленного.

Конденсированный код 688 711 684:

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

Быстрая версия ( 720 693)

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

Более читаемая версия:

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

Версия без улучшения поведения 615:

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

Ответ 27

Scala, 368 символов

Во-первых, четкая версия с 592 символами:

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

Выход консоли выглядит следующим образом:

$ 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

Мы можем сделать агрессивную минизацию и довести ее до 415 символов:

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

Сеанс консоли выглядит следующим образом:

$ 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

Я уверен, что эксперт Scala может сделать еще лучше.

Обновление: В комментариях Томас дал еще более короткую версию: 368 символов:

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

Незначительно, при 375 символах:

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

Ответ 28

Scala 2.8, 311 314 320 330 332 336 < забастовкa > 341 375 символы

включая длинную настройку слова. Идеи, заимствованные из других решений.

Теперь как 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)

Запустить с помощью

scala -howtorun:script a.scala alice.txt

BTW, редактирование с 314 до 311 символов фактически удаляет только 1 символ. Кто-то неправильно подсчитал (Windows CRs?).

Ответ 29

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

Несколько более разборчиво:

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

Ответ 30

Java - 896 символов

931 символов

1233 символа сделаны нечитаемыми

1977 символ "несжатый"


Обновление: я агрессивно уменьшил количество символов. Опускает однобуквенные слова по обновленной спецификации.

Я очень завидую С# и 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)+" ");}}}

"читаемый":

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

Вывод Алисы:

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

Выход Дон Кихота (также из Гутенберга):

 ________________________________________________________________________
|________________________________________________________________________| that
|________________________________________________________| he
|______________________________________________| for
|__________________________________________| his
|________________________________________| as
|__________________________________| with
|_________________________________| not
|_________________________________| was
|________________________________| him
|______________________________| be
|___________________________| don
|_________________________| my
|_________________________| this
|_________________________| all
|_________________________| they
|________________________| said
|_______________________| have
|_______________________| me
|______________________| on
|______________________| so
|_____________________| you
|_____________________| quixote