Построить таблицу 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 символы (убедитесь, что вы учитываете возможные различия длины строки и слова: например: второе наиболее распространенное слово может быть намного длиннее первого, но не сильно отличается по частоте). Увеличьте ширину полосы в пределах этих ограничений и масштабируйте полосы соответственно (согласно частотам, которые они представляют).

Пример:

Текст для примера можно найти здесь (Приключения Алисы в стране чудес, Льюис Кэрролл).

Этот конкретный текст даст следующий график:

 _________________________________________________________________________ | _________________________________________________________________________ | она | _______________________________________________________________ | Вы | ____________________________________________________________ | сказал | ____________________________________________________ | Алиса | ______________________________________________ | был | __________________________________________ | что | ___________________________________ | как | _______________________________ | ее | ____________________________ | с | ____________________________ | в | ___________________________ | s | ___________________________ | т | _________________________ | на | _________________________ | все | ______________________ | это | ______________________ | для | ______________________ | имел | _____________________ | но | ____________________ | быть | ____________________ | не | ___________________ | они | __________________ | так 

К вашему сведению: это частоты, на которых построен график выше:

[("она", 553), ("ты", 481), ("сказал", 462), ("Алиса", 403), ("был", 358), ("что
', 330), ('as', 274), ('her', 248), ('with', 227), ('at', 227), ('s', 219), ('t', 218), ('on', 204), ('all', 200), ('this', 181), ('for', 179), ('had', 178), ('
но ", 175), (" быть ", 167), (" не ", 166), (" они ", 155), (" так ", 152)]

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

 ________________________________________________________________
| ________________________________________________________________ | она 
|_______________________________________________________| superlongstringstring 
|_____________________________________________________| сказал 
| ______________________________________________ | Алиса 
| ________________________________________ | было 
| _____________________________________ | тот 
| ______________________________ | как 
| ___________________________ | ей 
| _________________________ | с 
| _________________________ | в 
| ________________________ | s 
| ________________________ | T 
| ______________________ | на 
| _____________________ | все 
| ___________________ | этот 
| ___________________ | за 
| ___________________ | имел 
| __________________ | но 
| _________________ | быть 
| _________________ | не 
| ________________ | O ни 
| ________________ | так 

Победитель:

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


Редактировать: Таблица с подведением итогов (2012-02-15) (первоначально добавлено пользователем Nas Banov):

Язык Relaxed Строгий
=========         =======  ======
GolfScript          130     143
Perl                        185
Windows PowerShell  148     199
Mathematica                 199
Рубин 185     205
Unix Toolchain      194     228
Python              183     243
Clojure                     282
Скала 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

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

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

59 ответов

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

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

код labVIEW

Результаты

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

объяснение кода labVIEW

Рубин 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.

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

Редактировать 2: Штеф указал, что я забыл конечный пробел - исправил это.

Редактировать 3: снова убрал завершающий пробел;)

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

Медленно - 3 минуты для образца текста (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*'| '@}/

Объяснение:

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

"Правильно" (надеюсь). (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*'| '@}/

Менее медленно - полминуты. (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*'| '@}/

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

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

Спасибо Гейбу за несколько полезных советов по уменьшению количества персонажей.

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

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 @

Читаемая версия

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 @

Выход

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

206

shell, grep, tr, grep, sort, uniq, sort, голова, 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

хм, только что видел выше: sort -nr -> sort -n а потом head -> tail => 208:)
update2: эээ, конечно вышеупомянутое глупо, поскольку тогда это будет полностью изменено. Итак, 209.
update3: оптимизировано регулярное выражение исключения -> 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$_"'



для удовольствия, вот версия только для Perl (намного быстрее):

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

Рубин 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

Редактировать: положить 'Put' обратно, должно быть там, чтобы избежать вывода кавычек.
Edit2: измененный файл-> IO
Edit3: удалено / I
Edit4: убраны круглые скобки (f*1.0), пересчитаны
Edit5: использовать добавление строки для первой строки; расширять s на месте.
Edit6: Сделано м плавать, удалено 1,0. РЕДАКТИРОВАТЬ: не работает, меняет длину. РЕДАКТИРОВАТЬ: не хуже, чем раньше
Edit7: использовать STDIN.read,

Mathematica (297 284 248 244 242 199 символов) Чистый Функциональный

и тестирование закона Зипфа

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

Правка 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)

Выход

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

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

Закон Зипфа

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

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

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

 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]

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

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

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

Рефакторинг Regex (функция выбора больше не работает)
Сбрасывание 1 символа слова
Более эффективное определение для функции "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]&@@ 
  Transpose@Take[SortBy[Tally@StringSplit[ToLowerCase@Import@i, 
    RegularExpression@"(\\W|\\b(.|the|and|of|to|i[tns]|or)\\b)+"],Last], -22]
  • Заменены f с Transpose а также Slot (#1/#2) аргументы.
  • Нам не нужны вонючие скобки (используйте f@x вместо f[x] где возможно)

C# - 510 451 436 446 434 426 422 символа (минимизировано)

Не так коротко, но сейчас, наверное, правильно! Обратите внимание, что предыдущая версия не показывала первую строку столбцов, неправильно масштабировала столбцы, загружала файл вместо получения его из stdin и не включала в себя все необходимые детализации C#. Вы можете легко сбрить много ударов, если C# не нужно так много лишней хрени. Может быть, 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 символа с встроенным лендивизором (что делает его в 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));}}

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, Поскольку весь сценарий находится в одной строке, его написание в виде одной строки не должно представлять никаких трудностей:).

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

Обратите внимание, что эта версия нормализуется для случая. Это не сокращает решение, так как удаление ,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;

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 символов.

Более старая объясненная версия может быть найдена здесь.

Рубин, 215, 216, 218, 221, 224, 236, 237 символов

Обновление 1: Ура! Это связано с решением JSBձոգչ. Не могу придумать способ урезать больше:)

Обновление 2: играли в грязную игру в гольф. Изменено each в map сохранить 1 символ:)

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

обновление 4: [0] скорее, чем .first+3. (@Shtééf)

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

Обновление 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} "}

Обновление 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 

Python 2.x, широтный подход = 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 по 32 записи).


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's 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

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 (notElemwords "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 значения умножаются, что отменяет отрицание.

Python 3.1 - 245 229 символов

Я думаю, что использование 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.

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

Выход:

 _________________________________________________________________________ | _________________________________________________________________________ | она | _______________________________________________________________ | Вы | ____________________________________________________________ | сказал | ____________________________________________________ | Алиса | ______________________________________________ | был | ___________________________________________ | что | ___________________________________ | как | ________________________________ | ее | _____________________________ | в | _____________________________ | с | ____________________________ | s | ____________________________ | т | __________________________ | на | _________________________ | все | _______________________ | это | ______________________ | для | ______________________ | имел | ______________________ | но | _____________________ | быть | _____________________ | не | ___________________ | они | ___________________ | так 

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

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

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

Минимизировано (злоупотребление \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)}

PHP CLI версия (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

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 for@t[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 символов) содержит строки со словами длиннее, чем то, что будет найдено позже.

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

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's warn() вместо print - там было сохранено четыре символа. Использовал карту вместо foreach, но я чувствую, что в расколе может быть еще больше сбережений (join()). Тем не менее, получил его до 203 - может спать на нем. По крайней мере, Perl теперь под счетчиком "shell, grep, tr, grep, sort, uniq, sort, head, perl";)

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

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

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

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

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

Обновление 5: Депрессия сна заставила меня забыть о 22-строчном ограничении и последующем ограничении. Вернуться к 208 с теми, с которыми обрабатываются. Не так уж и плохо, 13 символов, чтобы справиться с этим, не конец света. Поиграл с встроенным eval в регулярном выражении Perl, но не смог заставить его работать и сохранять символы... лол. Обновлен пример, чтобы соответствовать текущему выводу.

Обновление 6: убраны лишние скобки, защищающие (...) для, так как синтаксическая конфета ++ позволяет с радостью подтолкнуть ее к. Благодаря вкладу Часов. Оуэнс (напоминая мой усталый мозг), нашел там решение для класса персонажей. Вернитесь к 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

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

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 

Общий 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)))))

Gawk - 336 (первоначально 507) персонажей

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

Хе хе! Я на мгновение опережаю [Matt's JavaScript][1] решение встречного вызова! ;) и [Питон AKX][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]
    }
}

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

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

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

Perl, 185 символов

200 (немного ломаных)199197195193187185 знаков. Последние два перевода строки являются значительными. Соответствует спецификации.

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

Первая строка загружает количество правильных слов в %X,

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

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

С (828)

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

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

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

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

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

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

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

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

  • Обновление 742 > 714 символов: обновлено в соответствии с комментариями Карла: удалено избыточное назначение (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);
 }
}

Выход:

 _________________________________________________________________________
| _________________________________________________________________________ | она
| _______________________________________________________________ | вы
| ____________________________________________________________ | сказал
| _____________________________________________________ | Алиса
| _______________________________________________ | было
| ___________________________________________ | тот
| ____________________________________ | как
| ________________________________ | ей
| _____________________________ | с
| _____________________________ | в
| __________________________ | на
| __________________________ | все
| _______________________ | этот
| _______________________ | за
| _______________________ | имел
| _______________________ | но
| ______________________ | быть
| _____________________ | не
| ____________________ | O ни
| ____________________ | так
| ___________________ | очень
| __________________ | какие

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

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

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

  • Замененный список со строкой []
  • Повторно использовал аргумент 'args' вместо объявления моего собственного массива String. Также использовал его в качестве аргумента.ToArray()
  • Заменен StringBuffer на String (да, да, ужасная производительность)
  • Заменяемая сортировка Java заменой выбора с ранней остановкой (должны быть найдены только первые 22 элемента)
  • Объединение некоторого объявления int в одно утверждение
  • Реализован не читерский алгоритм, находящий наиболее ограничивающую строку вывода. Реализовано это без ФП.
  • Исправлена ​​проблема сбоя программы, когда в тексте было менее 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);}}}

Clojure 282 строгий

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

Scala 2,8, 311 314 320 330 332 336 341 375 символов

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

Теперь как скрипт (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

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

Скала, 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)
  }
}

Еще один питон 2.x - 206 символов (или 232 с "полосой ширины")

Я верю этому, если полностью соответствует вопросу. Список игнорирования здесь, он полностью проверяет длину строки (см. Пример, где я заменил Alice от Aliceinwonderlandbylewiscarroll Через текст пятый элемент становится самой длинной строкой. Даже имя файла предоставляется из командной строки, а не жестко закодировано (жесткое кодирование удалит около 10 символов). У него есть один недостаток (но я считаю, что это нормально с вопросом), поскольку он вычисляет целочисленный делитель, чтобы сделать строку короче 80 символов, самая длинная строка короче 80 символов, а не точно 80 символов. Версия Python 3.x не имеет этого дефекта (но намного длиннее).

Также я считаю, что это не так сложно читать.

import sys,re
t=re.split("\W+(?:(?:the|and|o[fr]|to|a|i[tns]?)\W+)*",sys.stdin.read().lower())
b=sorted((-t.count(x),x)for x in set(t))[:22]
for l,w in b:print"|"+l/min(z/(78-len(e))for z,e in b)*'-'+"|",w

|----------------------------------------------------------------| she
|--------------------------------------------------------| you
|-----------------------------------------------------| said
|----------------------------------------------| aliceinwonderlandbylewiscarroll
|-----------------------------------------| was
|--------------------------------------| that
|-------------------------------| as
|----------------------------| her
|--------------------------| at
|--------------------------| with
|-------------------------| s
|-------------------------| t
|-----------------------| on
|-----------------------| all
|---------------------| this
|--------------------| for
|--------------------| had
|--------------------| but
|-------------------| be
|-------------------| not
|------------------| they
|-----------------| so

Поскольку не ясно, должны ли мы печатать максимальный бар в одной строке (как в примере вывода). Ниже еще один, который делает это, но 232 символа.

import sys,re
t=re.split("\W+(?:(?:the|and|o[fr]|to|a|i[tns]?)\W+)*",sys.stdin.read().lower())
b=sorted((-t.count(x),x)for x in set(t))[:22]
f=min(z/(78-len(e))for z,e in b)
print"",b[0][0]/f*'-'
for y,w in b:print"|"+y/f*'-'+"|",w

Python 3.x - 256 символов

Используя класс Counter из python 3.x, мы надеялись сделать его короче (так как Counter делает здесь все, что нам нужно). Оказывается, это не лучше. Ниже моя пробная 266 символов:

import sys,re,collections as c
b=c.Counter(re.split("\W+(?:(?:the|and|o[fr]|to|a|i[tns]?)\W+)*",
sys.stdin.read().lower())).most_common(22)
F=lambda p,x,w:print(p+'-'*int(x/max(z/(77.-len(e))for e,z in b))+w)
F(" ",b[0][1],"")
for w,y in b:F("|",y,"| "+w)

Проблема в том, что collections а также most_common очень длинные слова и даже Counter не коротка... правда, не пользуюсь Counter делает код только на 2 символа длиннее;-(

Python 3.x также вводит другие ограничения: деление двух целых чисел больше не является целым числом (поэтому мы должны привести к int), print теперь является функцией (необходимо добавить круглые скобки) и т. д. Вот почему получается на 22 символа длиннее, чем версия python2.x, но намного быстрее. Возможно, у более опытного программиста на Python 3.x появятся идеи по сокращению кода.

Другие вопросы по тегам