Zbuduj wykres ASCII z najczęściej używanymi słowami w danym tekście [zamknięte]

156

Wyzwanie:

Utwórz wykres ASCII z najczęściej używanymi słowami w danym tekście.

Zasady:

  • Akceptuj a-zi A-Z(znaki alfabetu) tylko jako część słowa.
  • Zignoruj ​​wielkość liter ( w naszym celu She== she).
  • Zignoruj ​​następujące słowa (dość arbitralne, wiem): the, and, of, to, a, i, it, in, or, is
  • Wyjaśnienie: biorąc pod uwagę don't: byłoby to przyjęte jako 2 różne „słowa” w zakresach a-zi A-Z: ( doni t).

  • Opcjonalnie (to zbyt późno, aby zostać formalnie zmianę specyfikacji teraz), który może zdecydować się odrzucać wszystkie single-literą „słowa” (może to potencjalnie powodują skrócenie listy ignorowanych zbyt).

Przetwórz dane text(przeczytaj plik określony za pomocą argumentów wiersza poleceń lub potokiem; przypuszczam us-ascii) i zbuduj nam plik word frequency charto następujących cechach:

  • Wyświetl tabelę (zobacz również poniższy przykład) dla 22 najczęściej używanych słów (uporządkowanych według malejącej częstotliwości).
  • Słupek widthprzedstawia liczbę wystąpień (częstotliwość) słowa (proporcjonalnie). Dodaj jedną spację i wydrukuj słowo.
  • Upewnij się, że te kreski (plus spacja-słowo-spacja) zawsze pasują : bar+ [space]+ word+ [space]powinno zawsze zawierać <= 80znaki (upewnij się, że uwzględniłeś możliwe różne długości kresek i słów: np .: drugie najczęściej używane słowo może być znacznie dłuższe niż pierwszy, choć nie różni się tak bardzo pod względem częstotliwości). Zmaksymalizuj szerokość słupków w ramach tych ograniczeń i odpowiednio skaluj słupki (zgodnie z reprezentowanymi przez nie częstotliwościami).

Przykład:

Tekst przykładu można znaleźć tutaj ( Alice's Adventures in Wonderland, autorstwa Lewisa Carrolla ).

Ten konkretny tekst dałby następujący wykres:

 _________________________________________________________________________
| _________________________________________________________________________ | Ona
| _______________________________________________________________ | ty
| ____________________________________________________________ | powiedziany
| ____________________________________________________ | alicja
| ______________________________________________ | był
| __________________________________________ | że
| ___________________________________ | tak jak
| _______________________________ | jej
| ____________________________ | z
| ____________________________ | w
| ___________________________ | s
| ___________________________ | t
| _________________________ | na
| _________________________ | wszystko
| ______________________ | to
| ______________________ | dla
| ______________________ | miał
| _____________________ | ale
| ____________________ | być
| ____________________ | nie
| ___________________ | one
| __________________ | więc


Dla twojej informacji: są to częstotliwości, na których zbudowany jest powyższy wykres:

[('she', 553), ('you', 481), ('said', 462), ('alice', 403), ('was', 358), ('that
', 330), (' as ', 274), (' ona ', 248), (' z ', 227), (' at ', 227), (' s ', 219), (' t '
, 218), ('on', 204), ('all', 200), ('this', 181), ('for', 179), ('had', 178), ('
ale ', 175), (' być ', 167), (' nie ', 166), (' oni ', 155), (' tak ', 152)]

Drugi przykład (aby sprawdzić, czy zaimplementowano pełną specyfikację): Zamień każde wystąpienie youw połączonym pliku Alicji w Krainie Czarów nasuperlongstringstring :

 ________________________________________________________________
| ________________________________________________________________ | Ona
| _______________________________________________________ | superlongstringstring
| _____________________________________________________ | powiedziany
| ______________________________________________ | alicja
| ________________________________________ | był
| _____________________________________ | że
| ______________________________ | tak jak
| ___________________________ | jej
| _________________________ | z
| _________________________ | w
| ________________________ | s
| ________________________ | t
| ______________________ | na
| _____________________ | wszystko
| ___________________ | to
| ___________________ | dla
| ___________________ | miał
| __________________ | ale
| _________________ | być
| _________________ | nie
| ________________ | one
| ________________ | więc

Zwycięzca:

Najkrótsze rozwiązanie (według liczby znaków, na język). Baw się dobrze!


Edycja : Tabela podsumowująca dotychczasowe wyniki (2012-02-15) (pierwotnie dodana przez użytkownika Nas Banov):

Język Łagodny Surowy
========= ======= ======
Kaczmarek 130 143
Perl 185
Windows PowerShell 148199
Mathematica 199
Wiśniewska 185 205
Unix Toolchain 194 228
Python 183 243
Clojure 282
Scala 311
Haskell 333
Awk 336
R 298
Javascript 304 354
Kaczor 321
Matlab 404
C # 422
Wiśniewska 386
PHP 450
F # 452
TSQL 483 507

Liczby przedstawiają długość najkrótszego rozwiązania w określonym języku. „Ścisłe” odnosi się do rozwiązania, które w pełni realizuje specyfikację (rysuje |____|słupki, zamyka pierwszą ____kreskę na górze linią, uwzględnia możliwość tworzenia długich słów z dużą częstotliwością itp.). „Zrelaksowany” oznacza, że ​​zdecydowano się na skrócenie pewnych swobód do rozwiązania.

Uwzględniane są tylko rozwiązania krótsze niż 500 znaków. Lista języków jest posortowana według długości rozwiązania „ścisłego”. „Unix Toolchain” oznacza różne rozwiązania, które używają tradycyjnej powłoki * nix oraz mieszanki narzędzi (takich jak grep, tr, sort, uniq, head, perl, awk).

ChristopheD
źródło
4
Cóż, „najdłuższy słupek” + słowo = 80 może nie mieścić się w granicach 80 kolumn, jeśli drugie najpopularniejsze słowo jest znacznie dłuższe. Myślę, że szukam „maksymalnego ograniczenia”.
Brian
1
Czy normalizujemy obudowę? „Ona” = „ona”?
Brian
2
IMO sprawiające, że to działa, zarówno pod względem czasu wykonania, jak i wykorzystania pamięci, wydaje się bardziej interesującym wyzwaniem niż liczba znaków.
Frank Farmer
81
Cieszę się, że moje ulubione słowa si tsą reprezentowane.
indyw
8
@indiv, @Nas Banov - głupi, zbyt prosty tokenizer czyta „nie” jako {didn, t} i „she's” jako {ona, s} :)
hobbs

Odpowiedzi:

123

LabVIEW 51 węzłów, 5 struktur, 10 diagramów

Nauczenie słonia stepowania nigdy nie jest ładne. Pominę liczbę znaków.

labVIEW code

wyniki

Program przebiega od lewej do prawej:

Wyjaśnienie kodu labVIEW

Joe Zoller
źródło
10
To nie jest tego warte
4
LabVIEW jest bardzo zadowolony ze swojej niszy do kontroli sprzętu i pomiarów, ale naprawdę okropny do manipulacji strunami.
Joe Z
19
Najlepsza odpowiedź na golfa, jaką widziałem. +1 za myślenie nieszablonowe!
Blair Holloway,
1
Muszę policzyć dla nas elementy ... liczy się każde pudełko i widżet, który musiałeś przeciągnąć na ekran.
dmckee --- kociak ex-moderator
1
Czy byłoby możliwe dodanie linku do większej wersji tych wykresów?
Svish
42

Ruby 1,9, 185 znaków

(w dużej mierze oparte na innych rozwiązaniach 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}]

Zamiast używać jakichkolwiek przełączników wiersza poleceń, takich jak inne rozwiązania, możesz po prostu przekazać nazwę pliku jako argument. (tj. ruby1.9 wordfrequency.rb Alice.txt)

Ponieważ używam tutaj literałów znakowych, to rozwiązanie działa tylko w Rubim 1.9.

Edycja: zastąpiono średniki podziałami wierszy dla „czytelności”. : P

Edycja 2: Shtéf wskazał, że zapomniałem spacji na końcu - naprawiłem to.

Edycja 3: ponownie usunięto spację;)

Ventero
źródło
Brakuje spacji na końcu, po każdym słowie.
Stéphan Kochen,
Aww strzelać, zignoruj ​​to. Wygląda na to, że golf został właśnie zaktualizowany i miejsce na końcu nie jest już wymagane. :)
Stéphan Kochen,
Czy wydaje się, że nie pasuje do „superlongstring” na drugiej lub późniejszej pozycji? (patrz opis problemu)
Nas Banov
2
Wygląda na to, że można to naprawić.
Zombies
39

GolfScript, 177 175 173 167 164 163 144 131 130 znaków

Wolno - 3 minuty dla przykładowego tekstu (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*'| '@}/

Wyjaśnienie:

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

„Dobrze” (miejmy nadzieję). (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*'| '@}/

Mniej wolno - pół minuty. (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*'| '@}/

Wyjście widoczne w dziennikach wersji.

Nabb
źródło
2
O GolfScript: golfscript.com/golfscript
Assaf Lavie
2
Nieprawidłowe, ponieważ jeśli drugie słowo jest naprawdę długie, przejdzie do następnej linii.
Gabe
5
„podziel przez zero” ... GolfScript na to pozwala?
JAB,
35

206

powłoka, grep, tr, grep, sort, uniq, sort, head, perl

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

hm, tak jak powyżej: sort -nr-> sort -na potem head-> tail=> 208 :)
update2: erm, oczywiście powyższe jest głupie, ponieważ zostanie wtedy odwrócone. Zatem 209.
update3: zoptymalizowano wyrażenie regularne wykluczania -> 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$_"'



dla zabawy, oto wersja tylko dla Perla (znacznie szybsza):

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

Transact SQL ustalane na podstawie rozwiązanie (SQL Server 2005) 1063 892 873 853 827 820 783 683 647 644 630 znaków

Dziękuję Gabe'owi za kilka przydatnych sugestii dotyczących zmniejszenia liczby znaków.

Uwaga: Dodane podziały wierszy w celu uniknięcia pasków przewijania wymagany jest tylko ostatni podział wiersza.

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 @

Czytelna wersja

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 @

Wynik

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

I z długim sznurkiem

 _______________________________________________________________ 
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| Alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| at
|_________________________| with
|_______________________| on
|______________________| all
|____________________| This
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| So
|________________| very
|________________| what
Martin Smith
źródło
12
Dałem ci +1, ponieważ zrobiłeś to w T-SQL i cytując Team America - „Masz jaja. Lubię piłki”.
Pozwoliłem sobie zamienić niektóre spacje na znaki nowej linii, aby uczynić je bardziej czytelnymi. Mam nadzieję, że nie schrzaniłem sprawy. Zminimalizowałem też trochę bardziej.
Gabe
3
Ten kod na mnie wrzeszczy! : O
Joey,
1
Dobrym sposobem na oszczędzanie jest zmiana 0.000na just 0, a następnie użycie -Czamiast 1.0/C. A co FLOATdo REALuratuje udar zbyt. Najważniejsze jest jednak to, że wygląda na to, że masz wiele ASinstancji, które powinny być opcjonalne.
Gabe
1
OK, a co powiesz na to SELECT [ ] FROM (SELECT $0 O, ' '+REPLICATE('_', MAX(C)*@F)+' ' [ ] FROM # UNION SELECT $1/C, '|'+REPLICATE('_',C*@F)+'| '+W FROM #)X ORDER BY O?
Gabe
34

Ruby 207 213 211 210 207 203 201 200 znaków

Ulepszenie Anurag, zawierające sugestię od rfusca. Usuwa również argumenty do sortowania i kilka innych drobnych golfistów.

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

Wykonaj jako:

ruby GolfedWordFrequencies.rb < Alice.txt

Edycja: wstaw 'wstawienia' z powrotem, musi tam być, aby uniknąć cudzysłowów na wyjściu.
Edit2: Zmieniono
plik- > IO Edit3: usunięto / i
Edit4: Usunięto nawiasy wokół (f * 1.0), ponownie
zliczono Edit5: Użyj dodawania ciągu w pierwszej linii; rozwijać się sw miejscu.
Edit6: Zmieniono m float, usunięto 1.0. EDYCJA: Nie działa, zmienia długości. EDYCJA: Nie gorzej niż przed
Edit7: Użyj STDIN.read.

archgoon
źródło
+1 - uwielbiam sortowanie, bardzo sprytne :)
Anurag
Hej, mała optymalizacja w porównaniu z wymyślaniem większości. :)
archgoon
Miły! Dodano dwie zmiany, które wprowadziłem również w wersji Anurag. Goli kolejne 4.
Stéphan Kochen
Rozwiązanie odbiegało od oryginalnego wyniku. Zamierzam sprawdzić, gdzie to się stało.
archgoon
1
Dalej jest krótszy wariant.
archgoon
28

Mathematica ( 297 284 248 244 242 199 znaków) Pure Functional

oraz badanie prawa Zipfa

Spójrz Mamo… bez vars, bez rąk… bez głowy

Edycja 1> zdefiniowano niektóre skróty (284 znaki)

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]

Kilka wyjaśnień

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)

Wynik

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

Mathematica nie nadaje się dobrze do gry w golfa, a to tylko z powodu długich, opisowych nazw funkcji. Funkcje takie jak „RegularExpression []” lub „StringSplit []” sprawiają, że szlocham :(.

Testowanie prawa firmy Zipf

Prawo Zipfa przewiduje, że w przypadku tekstu w języku naturalnym wykres log (ranga) vs log (liczba wystąpień) zachowuje zależność liniową .

Prawo to jest wykorzystywane przy opracowywaniu algorytmów kryptografii i kompresji danych. (Ale to NIE jest "Z" w algorytmie LZW).

W naszym tekście możemy to przetestować w następujący sposób

 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]

Wynik jest (dość dobrze liniowy)

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

Edytuj 6> (242 znaki)

Refaktoryzacja wyrażenia regularnego (nie ma już funkcji Select)
Porzucenie 1 słów znakowych
Bardziej wydajna definicja funkcji „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]

Edytuj 7 → 199 znaków

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]
  • Zastąpiono fz Transposei Slot( #1/ #2) argumentów.
  • Nie potrzebujemy śmierdzących nawiasów (używaj f@xzamiast, f[x]jeśli to możliwe)

belisarius
źródło
9
Myślisz, że „RegularExpression” jest złe? Płakałem, kiedy wpisałem „System.Text.RegularExpressions.Regex.Split” w wersji C #, dopóki nie zobaczyłem kodu Objective-C: „stringWithContentsOfFile”, „enumerateSubstringsInRange”, „NSStringEnumerationByWords”, „sortArrayUsingComparator” i .
Gabe
2
@ Gabe Dzięki ... Teraz czuję się lepiej. W języku hiszpańskim mówimy „mal de muchos, consuelo de tontos” .. Coś w rodzaju „Wielu zmartwionych, głupców ulżyło”: D
Dr. belisarius
1
Element |i|jest zbędny w Twoim wyrażeniu regularnym, ponieważ już go masz .|.
Gabe
1
Podoba mi się to hiszpańskie powiedzenie. Najbliższą rzeczą, jaką przychodzi mi do głowy po angielsku, jest „nędza kocha towarzystwo”. Oto moja próba tłumaczenia: „To głupiec, który cierpiąc pociesza myślenie o innych w tej samej sytuacji”. Przy okazji niesamowita praca nad implementacją Mathematica.
dreeves
@dreeves Głupota przekroczyć barierę językową łatwo ... Cieszę się, że podoba Ci się mój mały program Mathematica, jestem dopiero zaczynają uczyć się języka
dr Belizariusz
26

C # - 510 451 436 446 434 426 422 znaków (minified)

Nie tak krótko, ale teraz prawdopodobnie poprawne! Uwaga, poprzednia wersja nie pokazywała pierwszego wiersza słupków, nie skalowała słupków poprawnie, pobierała plik zamiast pobierać go ze standardowego wejścia i nie zawierała całej wymaganej oznajmialności C #. Możesz łatwo zgolić wiele pociągnięć, gdyby C # nie potrzebował tak wielu dodatkowych bzdur. Może Powershell mógłby zrobić lepiej.

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 znaki z wbudowanym lendivisorem (co sprawia, że ​​jest 22 razy wolniejsze) w poniższej formie ( znaki nowej linii używane dla wybranych spacji):

using System.Linq;using C=System.Console;class M{static void Main(){var
a=System.Text.RegularExpressions.Regex.Split(C.In.ReadToEnd().ToLower(),@"(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|\W)+").GroupBy(x=>x).OrderBy(x=>-x.Count()).Take(22);var
b=a.Select(x=>new{p=new string('_',(int)(x.Count()/a.Max(y=>y.Count()/(76d-y.Key.Length)))),t=x.Key}).ToList();C.WriteLine(" "+b[0].p);b.ForEach(x=>C.WriteLine("|"+x.p+"| "+x.t));}}
Gabe
źródło
+1 dla sprytnego tyłka pobierającego plik w tekście. :)
sarnold
1
Ukradnij krótki adres URL z odpowiedzi Matta.
indyk
2
Zgodnie ze specyfikacją plik musi zostać przesłany potokiem lub przekazany jako argumenty. Jeśli założyć, że argumenty [0] zawierają lokalną nazwę pliku, możesz ją znacznie skrócić, używając argumentów [0] zamiast (new WebClient ()). DownloadString (@ " gutenberg.org/files/11/11. txt " ) -> zaoszczędziłoby ci to około 70 znaków
thorkia
1
Oto wersja zastępująca wywołanie WebClient z argumentami 0, wywołanie StreamReader i usuwająca kilka dodatkowych spacji. Całkowita liczba znaków = 413 var a = Regex.Replace ((new StreamReader (args [0])). ReadToEnd (), "[^ a-zA-Z]", "") .ToLower (). Split ('' ) .Gdzie (x =>! (Nowy [] {"the", "and", "of", "to", "a", "i", "it", "in", "or", " to "}). Zawiera (x)). GroupBy (x => x) .Wybierz (g => new {w = g.Key, c = g.Count ()}). OrderByDescending (x => xc). Skip (1) .Take (22) .ToList (); var m = a.OrderByDescending (x => xc) .First (); a.ForEach (x => Console.WriteLine ("|" + new String (' _ ', xc * (80-mwLength-4) / mc) + "|" + xw));
thorkia
„Nowy StreamReader” bez „używania” jest brudny. File.ReadAllText (args [0]) lub Console.In.ReadToEnd () są znacznie lepsze. W tym drugim przypadku możesz nawet usunąć argument z Main (). :)
Rotsor
25

Perl, 237 229 209 znaków

(Zaktualizowany ponownie, aby pokonać wersję Ruby, wprowadzając więcej brudnych sztuczek golfowych, zastępując split/[^a-z/,lcje lc=~/[a-z]+/gi eliminując sprawdzanie pustego ciągu w innym miejscu. Zostały one zainspirowane wersją Ruby, więc kredyt jest należny.)

Aktualizacja: teraz z Perlem 5.10! Wymień printsię sayi używać ~~, aby uniknąć map. To musi być wywołane w linii poleceń jako perl -E '<one-liner>' alice.txt. Ponieważ cały skrypt znajduje się w jednej linii, napisanie go jako jednowierszowego nie powinno sprawiać trudności :).

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

Zauważ, że ta wersja normalizuje wielkość liter. Nie skraca to żadnego rozwiązania, ponieważ usunięcie ,lc(dla małych liter) wymaga dodania A-Zdo podzielonego wyrażenia regularnego, więc jest to mycie.

Jeśli jesteś w systemie, w którym znak nowej linii to jeden znak, a nie dwa, możesz skrócić ten znak o kolejne dwa znaki, używając dosłownego znaku nowej linii zamiast \n. Jednak nie napisałem powyższej próbki w ten sposób, ponieważ jest ona „jaśniejsza” (ha!) W ten sposób.


Oto w większości poprawne, ale nie dość krótkie, rozwiązanie w Perlu:

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

Poniższe informacje są tak krótkie, jak to tylko możliwe, zachowując jednocześnie względną czytelność. (392 znaków).

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

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

print " " . "_" x $widest . "\n";
print"|" . "_" x int(($count{$_} / $count{$sorted[0]}) * $widest) . "| $_ \n" foreach @sorted;
JSB ձոգչ
źródło
Ma teraz kilka błędów; utrwalanie i skracanie.
JSB,
4
Nie dotyczy to przypadku, gdy drugie słowo jest znacznie dłuższe niż pierwsze, prawda?
Joey,
1
Oba foreachs można zapisać jako fors. To 8 znaków w dół. Następnie masz grep{!($_~~@s)}map{lc=~/[a-z]+/g}<>, który, jak sądzę, można zapisać jako grep{!(/$_/i~~@s)}<>=~/[a-z]+/gzejście o 4 więcej w dół. Wymień " "się $"i jesteś w dół 1 więcej ...
Zaid
sort{$c{$b}-$c{$a}}...zaoszczędzić jeszcze dwa. Możesz też po prostu przejść %czamiast keys %cdo sortfunkcji i zapisać cztery kolejne.
tłum
20

Windows PowerShell, 199 znaków

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

(Ostatni podział wiersza nie jest konieczny, ale został zawarty tutaj w celu zwiększenia czytelności).

(Aktualny kod i moje pliki testowe są dostępne w moim repozytorium SVN . Mam nadzieję, że moje przypadki testowe wychwytują najczęstsze błędy (długość paska, problemy z dopasowywaniem wyrażeń regularnych i kilka innych))

Założenia:

  • US ASCII jako dane wejściowe. Prawdopodobnie robi się dziwnie z Unicode.
  • Co najmniej dwa nieprzerwane słowa w tekście

Historia

Wersja zrelaksowana (137), ponieważ jest to teraz liczone osobno, najwyraźniej:

($x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *)[-1..-22]|%{"|$('_'*(76*$_.Count/$x[-1].Count))| "+$_.Name}
  • nie zamyka pierwszego paska
  • nie uwzględnia długości słowa innego niż pierwsze

Odchylenia długości słupków jednego znaku w porównaniu z innymi rozwiązaniami wynikają z tego, że program PowerShell używa zaokrąglania zamiast obcinania podczas konwersji liczb zmiennoprzecinkowych na liczby całkowite. Ponieważ zadanie wymagało tylko proporcjonalnej długości pręta, powinno to być w porządku.

W porównaniu do innych rozwiązań przyjąłem nieco inne podejście do określania najdłuższego paska, po prostu wypróbowując i przyjmując najwyższą taką długość, gdy żadna linia nie ma więcej niż 80 znaków.

Starszą wersję wyjaśnioną można znaleźć tutaj .

lubi
źródło
Imponujące, wydaje się, że Powershell to odpowiednie środowisko do gry w golfa. Twoje podejście do długości paska jest dokładnie tym, co próbowałem opisać (przyznaję, że nie tak genialnie) w specyfikacji.
ChristopheD,
1
@ChristopheD: Z mojego doświadczenia (Anarchy Golf, niektóre zadania Project Euler i kilka innych zadań tylko dla przyjemności), PowerShell jest zwykle tylko nieznacznie gorszy niż Ruby i często powiązany lub lepszy niż Perl i Python. Nie ma jednak odpowiednika dla GolfScript. Ale z tego, co widzę, może to być najkrótsze rozwiązanie, które poprawnie uwzględnia długości prętów ;-)
Joey
Najwyraźniej miałem rację. Powershell może działać lepiej - znacznie lepiej! Proszę podać rozszerzoną wersję z komentarzami.
Gabe
JOHANNES: Próbowałeś -split("\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z]")? Mi to pasuje.
Gabe
Nie zapomnij o interpolacji ciągu wyjściowego: "|$('_'*($w*$_.count/$x[0].count))| $($_.name) "(lub wyeliminuj ostatnią spację, ponieważ jest to w pewnym sensie automatyczne). Możesz użyć, -split("(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z])+")aby zaoszczędzić kilka więcej, nie uwzględniając spacji (lub użyj [-2..-23]).
Gabe
19

Ruby, 215, 216 , 218 , 221 , 224 , 236 , 237 znaków

aktualizacja 1: Hurra ! Jest to wiązać z JS Bangs " rozwiązania . Nie mogę wymyślić sposobu, aby już ciąć :)

aktualizacja 2: zagrał brudną sztuczkę golfową. Zmieniono eachna, mapaby zapisać 1 postać :)

aktualizacja 3: zmieniona File.readna IO.read+2. Array.group_bynie był zbyt owocny, zmieniono na reduce+6. Sprawdzanie bez rozróżniania wielkości liter nie jest potrzebne po małej wielkości liter downcasew wyrażeniu regularnym +1. Sortowanie malejąco można łatwo przeprowadzić, negując wartość +6. Całkowite oszczędności +15

aktualizacja 4: [0]zamiast .first+3. (@ Shtééf)

Aktualizacja 5: Rozwiń zmienną lw miejscu, +1. Rozwiń zmienną sw miejscu, +2. (@ Shtééf)

Aktualizacja 6: Użyj dodawania ciągów zamiast interpolacji dla pierwszej linii, +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} "}

aktualizacja 7: Przeszedłem przez wiele rzeczy, aby wykryć pierwszą iterację wewnątrz pętli, używając zmiennych instancji. Mam tylko +1, chociaż być może jest potencjał. Zachowanie poprzedniej wersji, bo uważam, że ta to czarna magia. (@ 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} "}

Czytelna wersja

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

Używać:

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

Wynik:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
Anurag
źródło
3
Czy „p” nie jest skrótem od „puts”? To mogłoby niektórych ogolić.
rfusca
1
Miły. Twoje użycie scandało mi jednak lepszy pomysł, więc znowu uzyskałem przewagę :).
JSB,
2
Musisz przeskalować słupki, aby najdłuższe słowo wraz ze słupkiem mieściło się w 80 znakach. Jak zasugerował Brian, długie drugie słowo przerwie twój program.
Gabe
3
Zastanawiam się, dlaczego wciąż gromadzą głosy. Rozwiązanie jest niepoprawne (w ogólnym przypadku) i dwukierunkowo krótsze rozwiązania Ruby są już dostępne.
Joey,
1
Teraz popraw mnie, jeśli się mylę, ale zamiast używać „małych liter”, dlaczego nie użyjesz flagi nieuwzględniającej wielkości liter REGEXP, która oszczędza 6-7 bajtów, prawda?
st0le
19

Python 2.x, podejście równoleżnikowe = 227 183 znaków

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

Pozwalając na swobodę w implementacji, skonstruowałem konkatenację ciągów, która zawiera wszystkie wyrazy wymagane do wykluczenia ( the, and, of, to, a, i, it, in, or, is) - a także wyklucza te dwa niesławne „słowa” soraz tz przykładu - i dodałem za darmo wykluczenie dla an, for, he. Wypróbowałem wszystkie konkatenacje tych słów z korpusem słów z Alicji, Biblii Króla Jakuba i pliku żargonu, aby sprawdzić, czy są jakieś słowa, które zostaną błędnie wykluczone przez ciąg. I tak zakończyłem z dwoma ciągami wykluczającymi: itheandtoforinisi andithetoforinis.

PS. zapożyczone z innych rozwiązań, aby skrócić kod.

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

Tyrada

Jeśli chodzi o słowa, które należy zignorować, można by pomyśleć, że zostaną one wzięte z listy najczęściej używanych słów w języku angielskim. Ta lista zależy od użytego korpusu tekstu . Według jednej z najpopularniejszych list ( 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 najpopularniejszych słów to:the be(am/are/is/was/were) to of and a in that have I

10 najpopularniejszych słów z tekstu Alicji w Krainie Czarów to the and to a of it she i you said
10 najpopularniejszych słów z pliku żargonu (wersja 4.4.7)the a of to and in is that or for

Pytanie brzmi więc, dlaczego orzostał uwzględniony na liście ignorowanych problemu, gdzie jest ~ 30 pod względem popularności, podczas gdy słowo that(8. najczęściej używane) nie jest. itd., itd. Dlatego uważam, że lista ignorowanych powinna być dostarczana dynamicznie (lub można ją pominąć).

Alternatywnym pomysłem byłoby po prostu pominięcie pierwszych 10 słów z wyniku - co w rzeczywistości skróciłoby rozwiązanie (elementarne - wystarczyłoby pokazać tylko wpisy od 11. do 32.).


Python 2.x, punktowe podejście = 277 243 znaków

Wykres narysowany w powyższym kodzie jest uproszczony (przy użyciu tylko jednego znaku na słupkach). Jeśli ktoś chce odtworzyć dokładnie wykres z opisu problemu (który nie był wymagany), ten kod to zrobi:

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

Mam problem z nieco przypadkowym wyborem 10 słów do wykluczenia, the, and, of, to, a, i, it, in, or, iswięc należy je przekazać jako parametry wiersza poleceń, na przykład:
python WordFrequencyChart.py the and of to a i it in or is <"Alice's Adventures in Wonderland.txt"

To jest 213 znaków + 30, jeśli weźmiemy pod uwagę "oryginalną" listę ignorowanych przekazaną w linii poleceń = 243

PS. Drugi kod również "dopasowuje" długości wszystkich górnych słów, więc żadne z nich nie przepełni się w zdegenerowanych przypadkach.

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|_____________________________________________________| said
|______________________________________________| alice
|_________________________________________| was
|______________________________________| that
|_______________________________| as
|____________________________| her
|__________________________| at
|__________________________| with
|_________________________| s
|_________________________| t
|_______________________| on
|_______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|___________________| not
|_________________| they
|_________________| so
Nas Banov
źródło
Jak dotąd fajne rozwiązanie, chociaż lista ignorowanych słów nie jest zaimplementowana (jeszcze), a paski są w tej chwili nieco prymitywne.
ChristopheD
@ChristopheD: był tam, ale nie było „instrukcji obsługi”. Właśnie dodałem tekst
paczki
Jeśli chodzi o listę języków i rozwiązań: poszukaj rozwiązań, które używają dzielenia wzdłuż \Wlub używają \bw wyrażeniu regularnym, ponieważ najprawdopodobniej nieone zgodne ze specyfikacją, co oznacza, że ​​nie będą dzielone na cyfry lub _mogą również nie usuwać słów pomijanych z ciągów takie jak the_foo_or123bar. Mogą nie pojawić się w tekście testu, ale specyfikacja jest dość jasna w tym przypadku.
Joey,
Niesamowita praca Nas, spędziłem popołudnie próbując to zoptymalizować i znalazłem tylko jedną poprawę. Możesz zmniejszyć sys.argvre.findall(r'\b(?!(?:the|and|.|of|to|i[tns]|or)\b)\w+',sys.stdin.read().lower())
liczbę
12

Haskell - 366 351 344 337 333 znaków

( mainDodano jeden podział wiersza w celu zwiększenia czytelności i brak konieczności podziału wiersza na końcu ostatniej linii).

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

Jak to działa, najlepiej widać, czytając argument od interacttyłu:

  • map f małe litery alfabetu, wszystko inne zastępuje spacjami.
  • words tworzy listę słów, porzucając oddzielające białe znaki.
  • filter (notElem words "the and of to a i it in or is")odrzuca wszystkie wpisy zawierające niedozwolone słowa.
  • group . sort sortuje słowa i grupuje identyczne w listy.
  • map hodwzorowuje każdą listę identycznych słów na krotkę formularza (-frequency, word).
  • take 22 . sort sortuje krotki według malejącej częstotliwości (pierwszy wpis krotki) i zachowuje tylko pierwsze 22 krotki.
  • b odwzorowuje krotki na słupki (patrz poniżej).
  • a poprzedza pierwszą linię podkreślenia, aby zakończyć najwyższy pasek.
  • unlines łączy wszystkie te linie razem z nowymi liniami.

Najtrudniejsze jest ustawienie odpowiedniej długości paska. Założyłem, że tylko podkreślenia liczą się do długości paska, więc ||będzie to słupek o zerowej długości. Funkcja bodwzorowuje c xnad x, gdzie xlista histogramy. Cała lista jest przekazywana do c, więc każde wywołanie cmoże obliczyć dla siebie współczynnik skalowania przez wywołanie u. W ten sposób unikam używania matematyki zmiennoprzecinkowej lub wymiernych, których funkcje konwersji i importy pochłaniałyby wiele znaków.

Zwróć uwagę na sztuczkę używania -frequency. Eliminuje to potrzebę ponieważ sortowania (rosnąco) będzie miejsca pierwsze słowa z największą częstotliwością. Później w funkcji mnożone są dwie wartości, co anuluje negację.reversesort-frequencyu-frequency

Thomas
źródło
Bardzo fajna robota (zagłosowałbym za, ale zabrakło głosów na dziś ze wszystkimi świetnymi odpowiedziami w tym wątku).
ChristopheD
Rani to moje oczy w sposób, którego bolesne jest nawet myślenie o opisaniu, ale wiele nauczyłem się Haskella, przekształcając go w czytelny kod. Dobra robota, sir. :-)
Owen S.
Właściwie to wciąż dość idiomatyczny Haskell, choć niezbyt wydajny. Krótkie nazwy sprawiają, że wygląda o wiele gorzej, niż jest w rzeczywistości.
Thomas,
@Thomas: Możesz to powtórzyć. :-)
Owen S.
1
divWłaściwie nie można go ruszyć ! Spróbuj - wynik jest nieprawidłowy. Powodem jest to, że wykonanie czynności divprzed *utratą precyzji.
MtnViewMark
11

JavaScript 1.8 (SpiderMonkey) - 354

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

Niestety, for([k,v]in z)wersja z Rhino nie wydaje się działać w SpiderMonkey i readFile()jest trochę łatwiejsza niż używanie, readline()ale przejście do 1.8 pozwala nam użyć zamknięć funkcji, aby wyciąć kilka dodatkowych linii ...

Dodanie spacji dla czytelności:

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

Stosowanie: js golf.js < input.txt

Wynik:

 _________________________________________________________________________ 
| _________________________________________________________________________ | Ona
| _______________________________________________________________ | ty
| ____________________________________________________________ | powiedziany
| ____________________________________________________ | alicja
| ______________________________________________ | był
| ___________________________________________ | że
| ___________________________________ | tak jak
| ________________________________ | jej
| _____________________________ | w
| _____________________________ | z
| ____________________________ | s
| ____________________________ | t
| __________________________ | na
| _________________________ | wszystko
| _______________________ | to
| ______________________ | dla
| ______________________ | miał
| ______________________ | ale
| _____________________ | być
| _____________________ | nie
| ___________________ | one
| ___________________ | więc

(wersja podstawowa - nieprawidłowo obsługuje szerokości prętów)

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

Myślę, że moja logika sortowania nie działa, ale… nie wiem. Naprawiono Brainfart.

Zminimalizowane (nadużycie \njest interpretowane jako ;czasami):

x={};p='|';e=' ';z=[]
readFile(arguments[0]).toLowerCase().replace(/\b(?!(the|and|of|to|a|i[tns]?|or)\b)\w+/g,function(y){x[y]?x[y].c++:z.push(x[y]={w:y,c:1})})
z=z.sort(function(a,b){return b.c-a.c}).slice(0,22)
for([k,v]in z){s=Array((v.c/z[0].c)*70|0).join('_')
if(!+k)print(e+s+e)
print(p+s+p+e+v.w)}
Matt
źródło
Ach, panie. Wierzę, że to twoja rękawica. Po raz drugi przemów do mnie.
dmckee --- kociak ex-moderator
2
Przy okazji - podoba mi się ten i[tns]?kawałek. Bardzo podstępnie.
dmckee --- kociak ex-moderator
@dmckee - dobrze zagrany, nie sądzę, żebym mógł pokonać twój 336, ciesz się twoim zasłużonym głosem :)
Matt
Zdecydowanie możesz pokonać 336 ... Dostępne jest cięcie 23 znaków - .replace(/[^\w ]/g, e).split(/\s+/).map(można je zastąpić .replace(/\w+/g,i użyć tej samej funkcji, co .map... Nie jestem również pewien, czy Rhino obsługuje function(a,b)b.c-a.cfunkcję sortowania zamiast funkcji sortowania (spidermonkey), ale to będzie shave {return }... b.c-a.cjest lepszym sortowaniem niż przy a.c<b.cokazji ... Edycja wersji Spidermonkey na dole z tymi zmianami
gnarf
Przeniosłem moją wersję SpiderMonkey na górę, ponieważ jest zgodna z ograniczeniem szerokości paska ... Udało mi się również wyciąć kilka dodatkowych znaków w oryginalnej wersji, używając ujemnego wyrażenia regularnego, aby zaprzeczyć słowom pozwalającym na pojedyncze zastąpienie (), i grałem w golfa kilka rzeczy z ?:doskonałą bazą do pracy!
gnarf
11

Wersja PHP CLI (450 znaków)

To rozwiązanie uwzględnia ostatni wymóg, który większość purystów z przekonaniem zdecydowała się zignorować. To kosztowało 170 znaków!

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

Minifikowane:

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

Czytelny dla człowieka:

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

?>

Wynik:

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

W przypadku długiego słowa słupki są odpowiednio dopasowane:

|--------------------------------------------------------| she
|---------------------------------------------------| thisisareallylongwordhere
|-------------------------------------------------| you
|-----------------------------------------------| said
|-----------------------------------------| alice
|------------------------------------| was
|---------------------------------| that
|---------------------------| as
|-------------------------| her
|-----------------------| with
|-----------------------| at
|--------------------| on
|--------------------| all
|------------------| this
|------------------| for
|------------------| had
|-----------------| but
|-----------------| be
|----------------| not
|---------------| they
|---------------| so
|--------------| very
user382874
źródło
11

Python 3.1 - 245 229 znaków

Myślę, że używanie Counter to rodzaj oszustwa :) Właśnie o tym przeczytałem około tydzień temu, więc była to doskonała okazja, aby zobaczyć, jak to działa.

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

Wydruki:

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

Część kodu została „pożyczona” z rozwiązania AKX.

sdolan
źródło
Brak pierwszego wiersza. A długość paska jest nieprawidłowa.
Joey,
w twoim kodzie wygląda na to, że open('!')czyta ze standardowego wejścia - która wersja / system operacyjny jest włączony? czy musisz nazwać plik „!”?
Nas Banov
Nazwij plik „!” :) Przepraszam, że to było dość niejasne i powinienem był o tym wspomnieć.
Sam Dolan,
11

Perl, 205 191 189 znaków / 205 znaków (w pełni wdrożone)

Niektóre części były inspirowane wcześniejszymi zgłoszeniami perl / ruby, kilka podobnych pomysłów zostało opracowanych niezależnie, inne są oryginalne. Krótsza wersja zawiera również pewne rzeczy, które widziałem / nauczyłem się z innych zgłoszeń.

Oryginalny:

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

Najnowsza wersja do 191 znaków:

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

Najnowsza wersja do 189 znaków:

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

Ta wersja (205 znaków) uwzględnia wiersze ze słowami dłuższymi niż te, które można znaleźć później.

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

Perl 203 202 201 198 195 208 203/231 znaków

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

Alternatywna, pełna implementacja ze wskazanym zachowaniem (globalne zgniatanie słupków) dla patologicznego przypadku, w którym słowo wtórne jest zarówno popularne, jak i wystarczająco długie, aby połączyć je do ponad 80 znaków ( ta implementacja to 231 znaków ):

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

W specyfikacji nigdzie nie było stwierdzenia, że ​​ma to iść do STDOUT, więc zamiast print, użyłem perla warn () - cztery znaki tam zapisane. Użyłem mapy zamiast foreach, ale wydaje mi się, że w podziale może być więcej oszczędności (join ()). Mimo to obniżyłem go do 203 - może na nim spać. Przynajmniej Perl znajduje się teraz pod opcją „shell, grep, tr, grep, sort, uniq, sort, head, perl” na razie liczba znaków;)

PS: Reddit mówi „Cześć”;)

Aktualizacja: Usunięto join () na rzecz przypisania i niejawnego złączenia konwersji skalarnej. Do 202. Zwróć też uwagę, że skorzystałem z opcjonalnej zasady „ignoruj ​​słowa z jednej litery”, aby zgolić 2 znaki, więc pamiętaj, że liczba częstotliwości to odzwierciedli.

Aktualizacja 2: Zamieniono przypisanie i niejawne połączenie za zabicie $ /, aby uzyskać plik jednym haustem, używając w pierwszej kolejności <>. Ten sam rozmiar, ale bardziej paskudny. Zamieniono, jeśli (! $ Y) {} na $ y || {} &&, zapisano 1 dodatkowy znak => 201.

Aktualizacja 3: Przejął kontrolę nad zmniejszaniem wielkości liter wcześnie (lc <>), przenosząc lc z bloku mapy - zamieniono oba wyrażenia regularne, aby nie używać już opcji / i, ponieważ nie jest już potrzebna. Zamieniono jawną warunkową konstrukcję x? Y: z dla tradycyjnego perlgolfa || niejawna konstrukcja warunkowa - /^...$/i?1:$x{$ } ++ dla /^...$/||$x{$ } ++ Zapisano trzy znaki! => 198, przełamał barierę 200. Może wkrótce zasnąć ... może.

Aktualizacja 4: Brak snu doprowadził mnie do szaleństwa. Dobrze. Bardziej szalony. Doszedłem do wniosku, że wystarczy przeanalizować zwykłe szczęśliwe pliki tekstowe, więc poddałem się, jeśli osiągnie wartość null. Uratowano dwie postacie. Zastąpiono „długość” krótszym o 1 znak (i ​​znacznie bardziej golfowym) y /// c - słyszysz, GolfScript? Idę po ciebie!!! szloch

Aktualizacja 5: Brak snu sprawił, że zapomniałem o limicie 22 rzędów i ograniczeniu kolejnej linii. Z powrotem do 208 z tymi obsługiwanymi. Nieźle, 13 postaci, które sobie z tym poradzą, to nie koniec świata. Bawiłem się regex inline eval perla, ale masz problemy z uruchomieniem go i zapisaniem znaków ... lol. Zaktualizowano przykład, aby pasował do bieżącego wyjścia.

Aktualizacja 6: Usunięto niepotrzebne szelki chroniące (...) dla, ponieważ syntaktyczny cukierek ++ pozwala na szczęśliwe wpychanie go w kierunku. Dzięki wkładowi Chasa. Owens (przypominając mój zmęczony mózg), znalazł tam rozwiązanie klasy postaci i [tns]. Powrót do 203.

Aktualizacja 7: Dodano drugą pracę, pełną implementację specyfikacji (w tym zachowanie pełnego ściskania kresek dla drugorzędnych długich słów, zamiast obcinania, które robi większość ludzi, w oparciu o oryginalną specyfikację bez patologicznego przypadku)

Przykłady:

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

Alternatywne wdrożenie na przykładzie przypadku patologicznego:

 _______________________________________________________________
|_______________________________________________________________| she
|_______________________________________________________| superlongstringstring
|____________________________________________________| said
|______________________________________________| alice
|________________________________________| was
|_____________________________________| that
|_______________________________| as
|____________________________| her
|_________________________| with
|_________________________| at
|_______________________| on
|______________________| all
|____________________| this
|____________________| for
|____________________| had
|____________________| but
|___________________| be
|__________________| not
|_________________| they
|_________________| so
|________________| very
|________________| what
Syntaera
źródło
Można skrócić regex dla słów zatrzymania przez zawaleniem is|in|it|isię i[snt]?- i wtedy nie ma różnicy z opcjonalnym reguły więcej. (Hm, nigdy bym nie pomyślał, żeby powiedzieć kolesiowi z Perla, jak zrobić Regex: D) - jedyny problem: muszę spojrzeć, jak mogę zgolić trzy bajty z mojego własnego rozwiązania, aby być znowu lepszym niż Perl: - |
Joey,
Ok, zignoruj ​​część tego, co powiedziałem wcześniej. Ignorowanie jednoliterowych słów jest rzeczywiście o bajt krótsze niż zaniechanie tego.
Joey,
Liczy się każdy bajt;) Rozważałem zrobienie sztuczki nowej linii, ale doszedłem do wniosku, że jest to w rzeczywistości ta sama liczba bajtów, nawet jeśli była to mniej drukowalnych znaków. Wciąż pracuję nad tym, czy uda mi się to jeszcze bardziej zmniejszyć :)
Syntaera
No cóż, normalizacja przypadku cofnęła mnie do 209. Nie wiem, co jeszcze mógłbym wyciąć. Chociaż PowerShell może być krótszy niż Perl. ;-)
Joey
Nie widzę, gdzie ograniczasz wyjście do 22 pierwszych słów, ani gdzie upewniasz się, że długie drugie słowo się nie zawija.
Gabe
9

F #, 452 znaków

Strightforward: pobierz sekwencję apar liczba słów, znajdź najlepszy mnożnik liczba słów na kolumnę k, a następnie wydrukuj wyniki.

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

Przykład (mam inną liczbę częstotliwości niż Ty, nie wiem dlaczego):

% app.exe < Alice.txt

 _________________________________________________________________________
|_________________________________________________________________________| she
|_______________________________________________________________| you
|_____________________________________________________________| said
|_____________________________________________________| alice
|_______________________________________________| was
|___________________________________________| that
|___________________________________| as
|________________________________| her
|_____________________________| with
|_____________________________| at
|____________________________| t
|____________________________| s
|__________________________| on
|_________________________| all
|_______________________| this
|______________________| had
|______________________| for
|_____________________| but
|_____________________| be
|____________________| not
|___________________| they
|__________________| so
Brian
źródło
okazuje się, że moje własne rozwiązanie było rzeczywiście trochę nieaktualne (z powodu trochę innej specyfikacji), rozwiązania odpowiadają teraz ;-)
ChristopheD
+1 za jedyną jak dotąd poprawną implementację skalowania
słupków
2
(@Rotsor: Ironiczne, biorąc pod uwagę, że moje jest najstarszym rozwiązaniem.)
Brian
Założę się, że można to trochę skrócić, łącząc etapy podziału, mapy i filtra. Spodziewałbym się również, że nie potrzebujesz tak wielu floats.
Gabe
Czy funkcje zagnieżdżania nie są zwykle krótsze niż użycie operatora potoku |>?
Joey,
8

Python 2.6, 347 znaków

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

Wynik:

 _________________________________________________________________________
|_________________________________________________________________________| she 
|_______________________________________________________________| you 
|____________________________________________________________| said 
|_____________________________________________________| alice 
|_______________________________________________| was 
|___________________________________________| that 
|____________________________________| as 
|________________________________| her 
|_____________________________| with 
|_____________________________| at 
|____________________________| s 
|____________________________| t 
|__________________________| on 
|__________________________| all 
|_______________________| this 
|_______________________| for 
|_______________________| had 
|_______________________| but 
|______________________| be 
|_____________________| not 
|____________________| they 
|____________________| so 
AKX
źródło
1
Możesz stracić linię, bm=(76.-len(W[0][0]))/W[0][1]ponieważ używasz bm tylko raz (stwórz następną linię U=lambda n:"_"*int(n*(76.-len(W[0][0]))/W[0][1]), goli 5 znaków. Ponadto: dlaczego miałbyś używać 2-znakowej nazwy zmiennej w kodowaniu golfa? ;-)
ChristopheD
W ostatnim wierszu spacja po druku nie jest konieczna, usuwa jeden znak
ChristopheD
1
Nie bierze pod uwagę przypadku, gdy drugie najczęstsze słowo jest bardzo długie, prawda?
Joey,
@ChristopheD: Ponieważ zbyt długo wpatrywałem się w ten kod. : P Dobry chwyt. @Johannes: To też można naprawić, tak. Nie jestem pewien, czy wszystkie inne implementacje to zrobiły, kiedy to napisałem.
AKX,
7

* sh (+ curl), częściowe rozwiązanie

To jest niekompletne, ale do diabła, oto częstotliwość słów licząca połowę problemu w 192 bajtach:

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

Gawk - 336 (pierwotnie 507) znaków

(po naprawieniu formatowania wyjściowego; naprawieniu skurczów; poprawieniu; poprawieniu ponownie; usunięciu całkowicie niepotrzebnego kroku sortowania; poprawieniu jeszcze raz; i jeszcze raz (ojej, ten zepsuł formatowanie); popraw jeszcze trochę; podejmując wyzwanie Matta, które desperacko poprawiam więc więcej; znalazłem inne miejsce, aby zaoszczędzić kilka, ale oddałem dwa, aby naprawić błąd długości pręta)

Heh heh! Na chwilę wyprzedzam wyzwanie związane z rozwiązaniem [Matt's JavaScript] [1] ! ;) i [python AKX] [2].

Wydaje się, że problem dotyczy języka, który implementuje natywne tablice asocjacyjne, więc oczywiście wybrałem taki, który ma okropnie wadliwy zestaw operatorów. W szczególności nie można kontrolować kolejności, w jakiej awk oferuje elementy mapy mieszającej, dlatego wielokrotnie skanuję całą mapę, aby znaleźć aktualnie najliczniejszą pozycję, drukuję ją i usuwam z tablicy.

To wszystko jest okropnie nieefektywne, przy wszystkich golfifccjach, które zrobiłem, stało się też dość okropne.

Minifikowane:

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

podziały wierszy służą wyłącznie celom przejrzystości: nie są konieczne i nie powinny być liczone.


Wynik:

$ 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

Czytelny; 633 znaków (pierwotnie 949):

{
    gsub("[^a-zA-Z]"," ");
    for(;NF;NF--)
    a[tolower($NF)]++
}
END{
    # remove "short" words
    split("the and of to a i it in or is",b," ");
    for (w in b) 
    delete a[b[w]];
    # Find the bar ratio
    d=1;
    for (w in a) {
    e=a[w]/(78-length(w));
    if (e>d)
        d=e
    }
    # Print the entries highest count first
    for (i=22; i; --i){               
    # find the highest count
    e=0;
    for (w in a) 
        if (a[w]>e)
        e=a[x=w];
        # Print the bar
    l=a[x]/d-2;
    # make a string of "_" the right length
    t=sprintf(sprintf("%%%dc",l)," ");
    gsub(" ","_",t);
    if (i==22) print" "t;
    print"|"t"| "x;
    delete a[x]
    }
}
dmckee
źródło
Dobra robota, dobrze, że dołączyłeś wersję z wcięciem / komentarzem ;-)
ChristopheD
7

Wspólny LISP, 670 znaków

Jestem nowicjuszem LISP-a i jest to próba użycia tablicy mieszającej do liczenia (więc prawdopodobnie nie jest to najbardziej kompaktowa metoda).

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

można uruchomić na przykład z cat alice.txt | clisp -C golf.lisp.

W czytelnej formie jest

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

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

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

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

       ; add alphabetic to current word, and bump word counter
       ; on non-alphabetic
       (cond
        ((char<= #\a x #\z)
         (push x w))
        (t
         (incf (gethash (concatenate 'string (reverse w)) c 0))
         (setf w nil)))))
6502
źródło
czy próbowałeś zainstalować niestandardowe makro czytnika, aby zmniejszyć rozmiar wejściowy?
Aaron,
@Aaron właściwie nie było to dla mnie trywialne, nawet samo uruchomienie tego ... :-) w przypadku rzeczywistej części golfowej użyłem tylko zmiennych jednoliterowych i to wszystko. W każdym razie, poza dość dużą szczegółowością, która jest nieodłącznie związana z CL dla tej skali problemów ("concatenate 'string", "setf" lub "gethash" to zabójcy ... w Pythonie są to "+", "=", "[]" ) nadal czułem to znacznie gorzej, niż bym się spodziewał, nawet na poziomie logicznym. W pewnym sensie mam wrażenie, że seplenienie jest w porządku, ale zwykłe seplenienie jest takie sobie i to poza nazywaniem (ponowne przeczytanie tego bardzo niesprawiedliwego komentarza, ponieważ moje doświadczenie z CL jest bliskie zeru).
6502
prawdziwe. Schemat ułatwiłby grę w golfa dzięki pojedynczej przestrzeni nazw. zamiast ciągowego dopisywania w każdym miejscu, możesz (letrec ((a string-append) (b gethash)) ... (a "x" "yz") ...)
Aaron
6

C (828)

Wygląda bardzo jak zaciemniony kod i używa glib dla stringów, list i hashów. Ilość Char ze wc -mmówi 828 . Nie uwzględnia słów jednoznakowych. Aby obliczyć maksymalną długość paska, bierze się pod uwagę najdłuższe możliwe słowo spośród wszystkich, a nie tylko pierwsze 22. Czy to odchylenie od specyfikacji?

Nie obsługuje awarii i nie zwalnia zajętej pamięci.

#include <glib.h>
#define S(X)g_string_##X
#define H(X)g_hash_table_##X
GHashTable*h;int m,w=0,z=0;y(const void*a,const void*b){int*A,*B;A=H(lookup)(h,a);B=H(lookup)(h,b);return*B-*A;}void p(void*d,void*u){int *v=H(lookup)(h,d);if(w<22){g_printf("|");*v=*v*(77-z)/m;while(--*v>=0)g_printf("=");g_printf("| %s\n",d);w++;}}main(c){int*v;GList*l;GString*s=S(new)(NULL);h=H(new)(g_str_hash,g_str_equal);char*n[]={"the","and","of","to","it","in","or","is"};while((c=getchar())!=-1){if(isalpha(c))S(append_c)(s,tolower(c));else{if(s->len>1){for(c=0;c<8;c++)if(!strcmp(s->str,n[c]))goto x;if((v=H(lookup)(h,s->str))!=NULL)++*v;else{z=MAX(z,s->len);v=g_malloc(sizeof(int));*v=1;H(insert)(h,g_strdup(s->str),v);}}x:S(truncate)(s,0);}}l=g_list_sort(H(get_keys)(h),y);m=*(int*)H(lookup)(h,g_list_first(l)->data);g_list_foreach(l,p,NULL);}
ShinTakezou
źródło
Nowe wiersze liczą się jako znaki, ale można usunąć dowolne wiersze, które nie są instrukcjami preprocesora. Jeśli chodzi o golfa, nie uważałbym, że nie uwalnianie pamięci jest złym ćwiczeniem.
Stéphan Kochen
ok ... umieść wszystko w jednej linii (spodziewaj się makr preproc) i daj vers bez zwalniania mema (i po usunięciu dwóch innych spacji ... można trochę ulepszyć "zaciemnianie", np. *v=*v*(77-lw)/mda 929. .. ale myślę, że może być dobrze, chyba że znajdę sposób, aby to zrobić dużo krócej)
ShinTakezou
Myślę, że można przenieść przynajmniej int cdo maindeklaracji i mainjest niejawnie int(bez typu jak są jakieś argumenty, AFAIK) main(c){...}. Prawdopodobnie mógłbyś też po prostu napisać 0zamiast NULL.
Joey,
robienie tego ... oczywiście spowoduje ostrzeżenie z włączoną flagą -Walllub z -std=c99włączoną flagą ... ale przypuszczam, że jest to bezcelowe dla golfa kodowego, prawda?
ShinTakezou,
uff, przepraszam za edycję z krótkimi przerwami, ... Powinienem zmienić Without freeing memory stuff, it reaches 866 (removed some other unuseful space)na coś innego, aby nie myśleć ludziom, że różnica w stosunku do wersji wolnej pamięci polega na tym: teraz wersja bez wolnej pamięci ma dużo więcej „ulepszeń”.
ShinTakezou,
6

Perl, 185 znaków

200 (lekko złamane) 199 197 195 193 187 185 znaków. Ostatnie dwie nowe linie są znaczące. Zgodny ze specyfikacją.

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

Pierwsza linia wczytuje liczbę ważnych słów do %X.

Drugi wiersz oblicza minimalny współczynnik skalowania, tak aby wszystkie wiersze wyjściowe miały <= 80 znaków.

Trzecia linia (zawiera dwa znaki nowej linii) generuje wynik.

mob
źródło
Nie spowoduje to usunięcia słów ignorowanych z ciągów znaków, takich jak „foo_the_bar”. Długość linii jest również o jeden za długa (przeczytaj ponownie specyfikację: „kreska + spacja + słowo + spacja <= 80 znaków”)
Joey
5

Java - 886 865 756 744 742 744 752 742 714 680 znaków

  • Aktualizacje przed pierwszym 742 : poprawione wyrażenie regularne, usunięte zbędne sparametryzowane typy, usunięte zbędne białe znaki.

  • Aktualizacja 742> 744 znaków : naprawiono hack o stałej długości. To zależy tylko od pierwszego słowa, a nie innych słów (jeszcze). Znalazłem kilka miejsc do skrócenia kodu ( \\sw wyrażeniu regularnym zastąpione i ArrayListzastąpione przez Vector). Szukam teraz krótkiego sposobu na usunięcie zależności Commons IO i czytania ze standardowego wejścia.

  • Aktualizacja 744> 752 znaki : Usunąłem zależność commons. Teraz czyta ze standardowego wejścia. Wklej tekst w stdin i naciśnij, Ctrl+Zaby uzyskać wynik.

  • Aktualizacja 752> 742 znaki : Usunąłem publici spację, nadałem nazwie klasy 1 znak zamiast 2, a teraz ignorowane są jednoliterowe słowa.

  • Aktualizacja 742> 714 znaków : Zaktualizowano zgodnie z uwagami Carl: usuwa zbędne przypisania (742> 730), zastąpionego m.containsKey(k)przez m.get(k)!=null(730> 728), wprowadzono substringing linii (728> 714).

  • Aktualizacja 714> 680 znaków : Zaktualizowano zgodnie z komentarzem Rotsora: poprawiono obliczanie rozmiaru paska, aby usunąć niepotrzebne rzucanie i poprawiono, split()aby usunąć niepotrzebne 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);}}

Bardziej czytelna wersja:

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

Wynik:

 _________________________________________________________________________
| _________________________________________________________________________ | Ona
| _______________________________________________________________ | ty
| ____________________________________________________________ | powiedziany
| _____________________________________________________ | alicja
| _______________________________________________ | był
| ___________________________________________ | że
| ____________________________________ | tak jak
| ________________________________ | jej
| _____________________________ | z
| _____________________________ | w
| __________________________ | na
| __________________________ | wszystko
| _______________________ | to
| _______________________ | dla
| _______________________ | miał
| _______________________ | ale
| ______________________ | być
| _____________________ | nie
| ____________________ | one
| ____________________ | więc
| ___________________ | bardzo
| __________________ | co

To do bani, że Java nie ma String#join()i zamyka (jeszcze).

Edycja autorstwa Rotsor:

Wprowadziłem kilka zmian w Twoim rozwiązaniu:

  • Zastąpiono listę ciągiem []
  • Ponownie wykorzystano argument „args” zamiast deklarować własną tablicę String. Użyto go również jako argumentu do .ToArray ()
  • Zastąpiono StringBuffer ciągiem (tak, tak, straszna wydajność)
  • Zamieniono sortowanie Java na sortowanie przez wybór z wczesnym zatrzymywaniem (należy znaleźć tylko pierwsze 22 elementy)
  • Zagregowano część deklaracji int w jedną instrukcję
  • Zaimplementowano algorytm nie oszukujący, znajdujący najbardziej ograniczającą linię wyjścia. Wdrożyłem to bez PR.
  • Naprawiono problem z awarią programu, gdy w tekście było mniej niż 22 różne słowa
  • Zaimplementowano nowy algorytm odczytu danych wejściowych, który jest szybki i tylko o 9 znaków dłuższy niż ten wolny.

Kod jest skondensowane 688 711 684 długo znakó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=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);}}}

Wersja szybka ( 720 693 znakó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);}}}

Bardziej czytelna wersja:

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

Wersja bez ulepszeń zachowania ma 615 znakó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,g=22;for(;j>0;){j=System.in.read();if(j>90)j-=32;if(j>64&j<91)w+=(char)j;else{if(!w.matches("^(|.|THE|AND|OF|TO|I[TNS]|OR)$"))m.put(w,m.get(w)!=null?m.get(w)+1:1);w="";}}l=m.keySet().toArray(l);for(;i<g;++i)for(j=i;++j<l.length;)if(m.get(l[i])<m.get(l[j])){w=l[i];l[i]=l[j];l[j]=w;}i=76-l[0].length();String s=new String(new char[i]).replace('\0','_');System.out.println(" "+s);for(k=0;k<g;k++){w=l[k];System.out.println("|"+s.substring(0,m.get(w)*i/m.get(l[0]))+"| "+w);}}}
BalusC
źródło
Czy nie mógłbyś po prostu użyć w pełni kwalifikowanej nazwy IOUtilszamiast importować ją? O ile wiem, i tak używasz go tylko raz.
Joey,
5
Trochę oszukiwałeś zakładając, że najdłuższy pasek będzie miał dokładnie 75 znaków. Musisz się upewnić, że żaden pasek + słowo nie jest dłuższy niż 80 znaków.
Gabe
Brakuje spacji po słowie. ;)
st0le
Jak już przycinanie dół moją odpowiedź , miałem nadzieję, że pobiłem złożenie BalusC użytkownika. Zostało mi jeszcze 200 znaków, ugh! Zastanawiam się, jak długo to by było bez założenia Commons IO i 75 znaków.
Jonathon Faust,
1
Wygląda na to, że możesz ogolić niektóre znaki, tworząc bString zamiast StringBuffer. Nie chcę jednak myśleć o tym, jaki byłby występ (zwłaszcza, że ​​dodajesz jedną postać na raz).
Michael Myers
4

Scala 2,8 311 314 320 330 332 336 341 375 znaków

w tym dostosowanie długich słów. Pomysły zapożyczone z innych rozwiązań.

Teraz jako skrypt ( 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)

Biegnij z

scala -howtorun:script a.scala alice.txt

BTW, edycja od 314 do 311 znaków w rzeczywistości usuwa tylko 1 znak. Ktoś wcześniej pomylił się w liczeniu (CR systemu Windows?).

mkneissl
źródło
4

Clojure 282 ścisłe

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

Nieco bardziej czytelnie:

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

Scala, 368 znaków

Po pierwsze, czytelna wersja w 592 znakach:

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

Wynik konsoli wygląda następująco:

$ 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

Możemy wykonać agresywną minifikację i zmniejszyć ją do 415 znaków:

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

Sesja konsoli wygląda następująco:

$ 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

Jestem pewien, że ekspert firmy Scala mógłby zrobić jeszcze lepiej.

Aktualizacja: W komentarzach Thomas podał jeszcze krótszą wersję, składającą się z 368 znaków:

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

Czytelnie, przy 375 znakach:

object Alice {
  def main(a:Array[String]) {
    val t = (Map[String, Int]() /: (
      for (
        x <- io.Source.fromFile(a(0)).getLines
        y <- "(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r.findAllIn(x)
      ) yield y.toLowerCase
    ).toList)((c, x) => c + (x -> (c.getOrElse(x, 0) + 1))).toList.sortBy(_._2).reverse.take(22)
    val w = 76 - t.head._1.length
    print (" "+"_"*w)
    t.map(s => "\n|" + "_" * (s._2 * w / t.head._2) + "| " + s._1).foreach(print)
  }
}
pr1001
źródło
383 znaki:object A{def main(a:Array[String]){val t=(Map[String, Int]()/:(for(x<-io.Source.fromFile(a(0)).getLines;y<-"(?i)\\w+\\b(?<!\\bthe|and|of|to|a|i|it|in|or|is)".r findAllIn x) yield y.toLowerCase).toList)((c,x)=>c+(x->(c.getOrElse(x,0)+1))).toList.sortBy(_._2).reverse.take(22);val w=76-t.head._1.length;print(" "+"_"*w);t map (s=>"\n|"+"_"*(s._2*w/t.head._2)+"| "+s._1) foreach print}}
Thomas Jung,
Oczywiście zawsze przydatny do zrozumienia! Miły!
pr1001
3

Java - 896 znaków

931 znaków

1233 znaki stały się nieczytelne

1977 znaków „nieskompresowanych”


Aktualizacja: agresywnie zmniejszyłem liczbę postaci. Pomija jednoliterowe słowa zgodnie ze zaktualizowaną specyfikacją.

Tak bardzo zazdroszczę C # i 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)+" ");}}}

"Czytelny":

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

Wyjście Alice:

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

Produkcja Don Kichota (także od Gutenberga):

 ________________________________________________________________________
|________________________________________________________________________| that
|________________________________________________________| he
|______________________________________________| for
|__________________________________________| his
|________________________________________| as
|__________________________________| with
|_________________________________| not
|_________________________________| was
|________________________________| him
|______________________________| be
|___________________________| don
|_________________________| my
|_________________________| this
|_________________________| all
|_________________________| they
|________________________| said
|_______________________| have
|_______________________| me
|______________________| on
|______________________| so
|_____________________| you
|_____________________| quixote
Jonathon
źródło
8
Całkowicie karp, czy naprawdę nie ma sposobu na skrócenie go w Javie? Mam nadzieję, że zapłaci wam liczba postaci, a nie funkcjonalność :-)
Nas Banov.