Erstellen Sie ein ASCII-Diagramm der am häufigsten verwendeten Wörter in einem bestimmten Text [geschlossen]


156

Die Herausforderung:

Erstellen Sie ein ASCII-Diagramm mit den am häufigsten verwendeten Wörtern in einem bestimmten Text.

Die Regeln:

  • Akzeptiere nur a-zund A-Z(alphabetische Zeichen) als Teil eines Wortes.
  • Gehäuse ignorieren ( She== shefür unseren Zweck).
  • Ignoriere die folgenden Wörter (ziemlich willkürlich, ich weiß): the, and, of, to, a, i, it, in, or, is
  • Klarstellung: Überlegung don't: Dies würde als 2 verschiedene "Wörter" in den Bereichen a-zund A-Z: ( donund t) genommen.

  • Optional (es ist zu spät formell die Spezifikationen nun sich zu ändern) Sie können Drop wählen , um alle einzelnen Buchstaben ‚Worte‘ (dies möglicherweise für eine Verkürzung der zu ignorieren Liste machen könnte).

Analysieren Sie eine gegebene text(lesen Sie eine Datei, die über Befehlszeilenargumente angegeben oder weitergeleitet wurde; nehmen Sie an us-ascii) und erstellen Sie eine word frequency chartmit den folgenden Eigenschaften:

  • Zeigen Sie das Diagramm (siehe auch das folgende Beispiel) mit den 22 häufigsten Wörtern an (geordnet nach absteigender Häufigkeit).
  • Die Bar width die Anzahl der Vorkommen (Häufigkeit) des Wortes (proportional) an. Fügen Sie ein Leerzeichen hinzu und drucken Sie das Wort.
  • Stellen Sie sicher, dass diese Balken (plus Leerzeichen-Wort-Leerzeichen) immer passen : bar+ [space]+ word+ [space]sollten immer <= 80Zeichen sein (berücksichtigen Sie mögliche unterschiedliche Balken- und Wortlängen: Beispiel: Das zweithäufigste Wort könnte dann viel länger sein die erste, obwohl sie sich nicht so stark in der Frequenz unterscheidet). Maximieren Sie die Balkenbreite innerhalb dieser Einschränkungen und skalieren Sie die Balken entsprechend (entsprechend den Frequenzen, die sie darstellen).

Ein Beispiel:

Den Text für das Beispiel finden Sie hier ( Alice's Adventures in Wonderland, von Lewis Carroll ).

Dieser spezifische Text würde die folgende Tabelle ergeben:

 _________________________________________________________________________
| _________________________________________________________________________ | sie
| _______________________________________________________________ | Sie
| ____________________________________________________________ | sagte
| ____________________________________________________ | Alice
| ______________________________________________ | war
| __________________________________________ | Das
| ___________________________________ | wie
| _______________________________ | ihr
| ____________________________ | mit
| ____________________________ | beim
| ___________________________ | s
| ___________________________ | t
| _________________________ | auf
| _________________________ | alles
| ______________________ | Dies
| ______________________ | zum
| ______________________ | hätten
| _____________________ | aber
| ____________________ | Sein
| ____________________ | nicht
| ___________________ | Sie
| __________________ | so


Zu Ihrer Information: Dies sind die Frequenzen, auf denen die obige Tabelle basiert:

[('sie', 553), ('du', 481), ('sagte', 462), ('alice', 403), ('war', 358), ('das'
', 330), (' as ', 274), (' her ', 248), (' with ', 227), (' at ', 227), (' s ', 219), (' t ')
, 218), ('on', 204), ('all', 200), ('this', 181), ('for', 179), ('had', 178), ('
aber ', 175), (' sei ', 167), (' nicht ', 166), (' sie ', 155), (' so ', 152)]

Ein zweites Beispiel (um zu überprüfen, ob Sie die vollständige Spezifikation implementiert haben): Ersetzen Sie jedes Vorkommen youin der verknüpften Alice im Wunderland- Datei durch superlongstringstring:

 ________________________________________________________________
| ________________________________________________________________ | sie
| _______________________________________________________ | Superlongstringstring
| _____________________________________________________ | sagte
| ______________________________________________ | Alice
| ________________________________________ | war
| _____________________________________ | Das
| ______________________________ | wie
| ___________________________ | ihr
| _________________________ | mit
| _________________________ | beim
| ________________________ | s
| ________________________ | t
| ______________________ | auf
| _____________________ | alles
| ___________________ | Dies
| ___________________ | zum
| ___________________ | hätten
| __________________ | aber
| _________________ | Sein
| _________________ | nicht
| ________________ | Sie
| ________________ | so

Der Gewinner:

Kürzeste Lösung (nach Zeichenanzahl pro Sprache). Habe Spaß!


Bearbeiten : Tabelle mit einer Zusammenfassung der bisherigen Ergebnisse (15.02.2012) (ursprünglich vom Benutzer Nas Banov hinzugefügt):

Sprache entspannt Entspannt
========= ======= ======
GolfScript 130 143
Perl 185
Windows PowerShell 148 199
Mathematica 199
Ruby 185 205
Unix Toolchain 194 228
Python 183 243
Clojure 282
Scala 311
Haskell 333
Awk 336
R 298
Javascript 304 354
Groovy 321
Matlab 404
C # 422
Smalltalk 386
PHP 450
F # 452
TSQL 483 507

Die Zahlen geben die Länge der kürzesten Lösung in einer bestimmten Sprache an. "Streng" bezieht sich auf eine Lösung, die die Spezifikation vollständig implementiert (zeichnet |____|Balken, schließt den ersten Balken oben mit einer ____Linie, berücksichtigt die Möglichkeit langer Wörter mit hoher Frequenz usw.). "Entspannt" bedeutet, dass einige Freiheiten genommen wurden, um die Lösung zu verkürzen.

Es sind nur Lösungen enthalten, die kürzer als 500 Zeichen sind. Die Liste der Sprachen ist nach der Länge der "strengen" Lösung sortiert. 'Unix Toolchain' wird verwendet, um verschiedene Lösungen zu kennzeichnen, die die traditionelle * nix-Shell sowie eine Mischung von Werkzeugen verwenden (wie grep, tr, sort, uniq, head, perl, awk).


4
Nun, 'längster Balken' + Wort = 80 passt möglicherweise nicht in 80 Spalten, wenn das zweithäufigste Wort ein viel längeres Wort ist. Ich denke, ich suche nach der 'maximalen Einschränkung'.
Brian

1
Normalisieren wir das Gehäuse? 'Sie' = 'sie'?
Brian

2
Die IMO, die dies sowohl hinsichtlich der Ausführungszeit als auch der Speichernutzung durchführt, scheint eine interessantere Herausforderung zu sein als die Anzahl der Zeichen.
Frank Farmer

81
Ich bin froh zu sehen, dass meine Lieblingswörter sund vertreten tsind.
Indiv

8
@indiv, @Nas Banov - alberner zu einfacher Tokenizer liest "nicht" als {didn, t} und "sie ist" als {sie, s} :)
hobbs

Antworten:


123

LabVIEW 51 Knoten, 5 Strukturen, 10 Diagramme

Dem Elefanten Stepptanz beizubringen ist nie schön. Ich werde die Anzahl der Zeichen überspringen.

labVIEW code

results

Das Programm läuft von links nach rechts:

labVIEW code explained


10
Es ist es nicht wert

4
LabVIEW ist sehr zufrieden mit seiner Hardware-Steuerungs- und Messnische, aber für die Manipulation von Strings wirklich ziemlich schrecklich.
Joe Z

19
Beste Code Golf Antwort, die ich gesehen habe. +1 für ein Denken über den Tellerrand hinaus!
Blair Holloway

1
Ich muss die Elemente für uns zählen ... jedes Feld und Widget, das Sie auf den Bildschirm ziehen mussten, zählt.
dmckee --- Ex-Moderator Kätzchen

1
Wäre es möglich, einen Link zu einer größeren Version dieser Diagramme hinzuzufügen?
Svish

42

Ruby 1,9, 185 Zeichen

(stark basierend auf den anderen Ruby-Lösungen)

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

Anstatt Befehlszeilenoptionen wie die anderen Lösungen zu verwenden, können Sie einfach den Dateinamen als Argument übergeben. (dh ruby1.9 wordfrequency.rb Alice.txt)

Da ich hier Zeichenliterale verwende, funktioniert diese Lösung nur in Ruby 1.9.

Bearbeiten: Semikolons durch Zeilenumbrüche ersetzt, um die Lesbarkeit zu gewährleisten. : P.

Edit 2: Shtééf wies darauf hin, dass ich den nachgestellten Leerzeichen vergessen habe - das wurde behoben.

Edit 3: Das nachfolgende Leerzeichen wieder entfernt;)


Nach jedem Wort fehlt das Leerzeichen.
Stéphan Kochen

Aww schießen, ignorieren Sie das. Es sieht so aus, als ob der Golf gerade aktualisiert wurde und kein Platz mehr benötigt wird. :)
Stéphan Kochen

Scheint nicht für "Superlongstringstring" in der 2. oder späteren Position zu passen? (siehe Problembeschreibung)
Nas Banov

2
Das sieht wirklich wartbar aus.
Zombies

39

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

Langsam - 3 Minuten für den Beispieltext (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*'| '@}/

Erläuterung:

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

"Richtig" (hoffentlich). (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*'| '@}/

Weniger langsam - eine halbe Minute. (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*'| '@}/

Ausgabe in Revisionsprotokollen sichtbar.



2
Nicht richtig, denn wenn das zweite Wort wirklich lang ist, wird es in die nächste Zeile umgebrochen.
Gabe

5
"durch Null teilen" ... GolfScript erlaubt das?
JAB

35

206

Shell, Grep, Tr, Grep, Sortieren, Uniq, Sortieren, Kopf, 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, gerade oben gesehen: sort -nr-> sort -nund dann head->tail => 208 :)
update2: ähm, natürlich ist das obige albern, da es dann umgekehrt wird. Also, 209.
update3: optimiert den Ausschluss regexp -> 206

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



Zum Spaß hier eine Nur-Perl-Version (viel schneller):

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

35

Transact SQL Set-basierte Lösung (SQL Server 2005) 1063 892 873 853 827 820 783 683 647 644 630 Zeichen

Vielen Dank an Gabe für einige nützliche Vorschläge zur Reduzierung der Zeichenanzahl.

Hinweis: Zeilenumbrüche wurden hinzugefügt, um Bildlaufleisten zu vermeiden. Es ist nur der letzte Zeilenumbruch erforderlich.

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 @

Lesbare Version

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 @

Ausgabe

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

Und mit der langen Schnur

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

12
Ich habe dir +1 gegeben, weil du es in T-SQL gemacht hast, und um Team America zu zitieren: "Du hast Bälle. Ich mag Bälle."

Ich habe mir erlaubt, einige Leerzeichen in Zeilenumbrüche umzuwandeln, um sie besser lesbar zu machen. Hoffentlich habe ich die Dinge nicht durcheinander gebracht. Ich habe es auch ein bisschen mehr minimiert.
Gabe

3
Dieser Code schreit mich an! : O
Joey

1
Eine gute Möglichkeit zum Speichern besteht darin, 0.000zu just zu wechseln 0und dann -Canstelle von zu verwenden 1.0/C. Und macht FLOATin REALwird auch einen Schlaganfall zu speichern. Das Größte ist jedoch, dass es so aussieht, als hätten Sie viele ASInstanzen, die optional sein sollten.
Gabe

1
OK, wie wäre es 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 Zeichen

Eine Verbesserung gegenüber Anurag, die Vorschläge von rfusca enthält. Entfernt auch Argumente zum Sortieren und einige andere kleinere Golfe.

w=(STDIN.read.downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).group_by{|x|x}.map{|x,y|[-y.size,x]}.sort.take 22;k,l=w[0];m=76.0-l.size;puts' '+'_'*m;w.map{|f,x|puts"|#{'_'*(m*f/k)}| #{x} "}

Ausführen als:

ruby GolfedWordFrequencies.rb < Alice.txt

Bearbeiten: Setzen Sie 'setzt' wieder ein, muss vorhanden sein, um zu vermeiden, dass Anführungszeichen in der Ausgabe enthalten sind.
Edit2: Geänderte Datei-> IO
Edit3: entfernt / i
Edit4: Entfernte Klammern um (f * 1.0), wiedergegeben
Edit5: Verwenden Sie die Zeichenfolgenaddition für die erste Zeile; erweitert sin-place.
Edit6: M schweben lassen, 1.0 entfernt. EDIT: Funktioniert nicht, ändert die Länge. EDIT: Nicht schlechter als zuvor
Edit7: Verwenden STDIN.read.


+1 - liebe das Sortieren, sehr klug :)
Anurag

Hey, kleine Optimierung im Vergleich dazu, den größten Teil davon zu entwickeln. :)
Archgoon

Nett! Zwei der Änderungen, die ich auch in Anurags Version vorgenommen habe, wurden hinzugefügt. Rasiert weitere 4.
Stéphan Kochen

Die Lösung ist von der ursprünglichen Ausgabe abgewichen. Ich werde versuchen herauszufinden, wo das passiert ist.
Archgoon

1
Es gibt eine kürzere Variante davon weiter unten.
Archgoon

28

Mathematica ( 297 284 248 244 242 199 Zeichen) Pure Functional

und Zipf's Law Testing

Schau Mama ... keine Vars, keine Hände, ... kein Kopf

Bearbeiten Sie 1> einige definierte Abkürzungen (284 Zeichen)

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]

Einige Erklärungen

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)

Ausgabe

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

Mathematica ist nicht gut zum Golfen geeignet, und das liegt nur an den langen, beschreibenden Funktionsnamen. Funktionen wie "RegularExpression []" oder "StringSplit []" lassen mich nur schluchzen :(.

Zipf's Law Testing

Das Zipf-Gesetz sagt voraus, dass für einen Text in natürlicher Sprache das Diagramm Log (Rang) vs Log (Vorkommen) einer linearen Beziehung folgt .

Das Gesetz wird bei der Entwicklung von Algorithmen für die Kriptographie und Datenkomprimierung verwendet. (Aber es ist NICHT das "Z" im LZW-Algorithmus).

In unserem Text können wir es mit folgendem testen

 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]

Das Ergebnis ist (ziemlich gut linear)

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

Bearbeiten Sie 6> (242 Zeichen)

Umgestaltung des Regex (keine Auswahlfunktion mehr)
Löschen von 1 Zeichenwörtern
Effizientere Definition für Funktion "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]

Bearbeiten Sie 7 → 199 Zeichen

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]
  • Ersetzt fdurch Transposeund Slot( #1/ #2) Argumente.
  • Wir brauchen keine stinkenden Klammern (verwenden f@xstatt f[x]wo möglich)


9
Sie denken, "RegularExpression" ist schlecht? Ich habe geweint, als ich "System.Text.RegularExpressions.Regex.Split" in die C # -Version eingegeben habe, bis ich den Objective-C-Code sah: "stringWithContentsOfFile", "enumerateSubstringsInRange", "NSStringEnumerationByWords", "sortedArrayUsingCompar" .
Gabe

2
@Gabe Danke ... mir geht es jetzt besser. Auf Spanisch sagen wir "mal de muchos, consuelo de tontos". Etwas wie "Viele beunruhigte, erleichterte Narren": D
Dr. belisarius

1
Das |i|ist in Ihrer Regex überflüssig, weil Sie bereits haben .|.
Gabe

1
Ich mag dieses spanische Sprichwort. Das Nächste, was ich mir auf Englisch vorstellen kann, ist "Elend liebt Gesellschaft". Hier ist mein Übersetzungsversuch: "Es ist ein Dummkopf, der, wenn er leidet, Trost findet, wenn er an andere in derselben Situation denkt." Erstaunliche Arbeit an der Mathematica-Implementierung, übrigens.
Dreeves

@dreeves Dummheit überwinden leicht die Sprachbarriere ... Schön zu sehen, dass Sie mein kleines Mathematica-Programm mögen, ich fange gerade an, die Sprache zu lernen
Dr. belisarius

26

C # - 510 451 436 446 434 426 422 Zeichen (minimiert)

Nicht so kurz, aber jetzt wahrscheinlich richtig! Beachten Sie, dass in der vorherigen Version die erste Zeile der Balken nicht angezeigt wurde, die Balken nicht richtig skaliert wurden, die Datei heruntergeladen wurde, anstatt sie von stdin abzurufen, und nicht alle erforderlichen C # -Verbosität enthalten waren. Sie könnten leicht viele Striche rasieren, wenn C # nicht so viel zusätzlichen Mist brauchte. Vielleicht könnte Powershell es besser machen.

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 Zeichen mit Lendivisor inline (was es 22-mal langsamer macht) in der folgenden Form (Zeilenumbrüche für ausgewählte Leerzeichen):

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

+1 für den Smart-Ass, der die Datei inline herunterlädt. :)
Sarnold

1
Stehlen Sie die kurze URL aus Matts Antwort.
indiv

2
Die Spezifikation besagt, dass die Datei als Args weitergeleitet oder übergeben werden muss. Wenn Sie davon ausgehen, dass args [0] den lokalen Dateinamen enthält, können Sie ihn erheblich verkürzen, indem Sie args [0] anstelle von (new WebClient ()) verwenden. DownloadString (@ " gutenberg.org/files/11/11. txt " ) -> es würde Sie ca. 70 Zeichen sparen
Thorkia

1
Hier ist eine Version, die den WebClient-Aufruf durch Argumente 0 ersetzt, einen Aufruf von StreamReader und das Entfernen einiger zusätzlicher Leerzeichen. Gesamtzahl der Zeichen = 413 var a = Regex.Replace ((neuer StreamReader (args [0])). ReadToEnd (), "[^ a-zA-Z]", "") .ToLower (). Split ('' ) .Wo (x =>! (Neu [] {"das", "und", "von", "bis", "a", "i", "es", "in", "oder", " ist "}). Enthält (x)). GroupBy (x => x). Wählen Sie (g => new {w = g.Key, c = g.Count ()}). OrderByDescending (x => xc). Überspringen (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

"neuer StreamReader" ohne "using" ist schmutzig. File.ReadAllText (args [0]) oder Console.In.ReadToEnd () sind viel besser. Im letzteren Fall können Sie sogar Argumente aus Ihrem Main () entfernen. :)
Rotsor

25

Perl, 237 229 209 Zeichen

(Wieder aktualisiert die Ruby - Version mit mehr schmutzig Golf Tricks zu schlagen, ersetzen split/[^a-z/,lcmitlc=~/[a-z]+/g , und einen Scheck für leere Zeichenkette an einem anderen Ort zu beseitigen. Diese inspiriert wurden durch die Ruby - Version, so Kredit , wem Ehre gebührt.)

Update: jetzt mit Perl 5.10! Ersetzen printdurch sayund verwenden Sie ~~, um a zu vermeiden map. Dies muss in der Kommandozeile als aufgerufen werden perl -E '<one-liner>' alice.txt. Da sich das gesamte Skript in einer Zeile befindet, sollte das Schreiben als Einzeiler keine Schwierigkeit darstellen :).

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

Beachten Sie, dass diese Version für den Fall normalisiert wird. Dies verkürzt die Lösung nicht, da Sie zum Entfernen ,lc(für das untere Gehäuse) A-Zden geteilten regulären Ausdruck hinzufügen müssen, sodass es sich um eine Wäsche handelt.

Wenn Sie sich in einem System befinden, in dem eine neue Zeile aus einem Zeichen und nicht aus zwei besteht, können Sie diese um zwei weitere Zeichen verkürzen, indem Sie anstelle von eine wörtliche neue Zeile verwenden \n. Allerdings habe ich das obige Beispiel nicht so geschrieben, da es so "klarer" (ha!) Ist.


Hier ist eine meist korrekte, aber nicht annähernd kurze Perl-Lösung:

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

Das Folgende ist ungefähr so ​​kurz wie es nur geht, während es relativ lesbar bleibt. (392 Zeichen).

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

Hat gerade ein paar Fehler; Fixieren und Verkürzen.
JSB 2

4
Dies gilt nicht für den Fall, dass das zweite Wort viel länger ist als das erste, oder?
Joey

1
Beide foreachs können als fors geschrieben werden . Das sind 8 Zeichen weniger. Dann haben Sie die grep{!($_~~@s)}map{lc=~/[a-z]+/g}<>, von der ich glaube, dass sie geschrieben werden könnte grep{!(/$_/i~~@s)}<>=~/[a-z]+/g, um 4 weitere nach unten zu gehen. Ersetzen Sie die " "durch $"und Sie sind unten 1 weitere ...
Zaid

sort{$c{$b}-$c{$a}}...zwei weitere zu retten. Sie können auch einfach %canstelle keys %cder sortFunktion übergeben und vier weitere speichern.
Mob

20

Windows PowerShell, 199 Zeichen

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

(Der letzte Zeilenumbruch ist nicht erforderlich, wird hier jedoch zur besseren Lesbarkeit angegeben.)

(Aktueller Code und meine Testdateien sind in meinem SVN-Repository verfügbar . Ich hoffe, dass meine Testfälle die häufigsten Fehler erkennen (Balkenlänge, Probleme mit dem Regex-Abgleich und einige andere).)

Annahmen:

  • US ASCII als Eingabe. Mit Unicode wird es wahrscheinlich komisch.
  • Mindestens zwei ununterbrochene Wörter im Text

Geschichte

Entspannte Version (137), da dies anscheinend inzwischen separat gezählt wird:

($x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *)[-1..-22]|%{"|$('_'*(76*$_.Count/$x[-1].Count))| "+$_.Name}
  • schließt den ersten Balken nicht
  • berücksichtigt nicht die Wortlänge des nicht ersten Wortes

Variationen der Balkenlängen eines Zeichens im Vergleich zu anderen Lösungen sind darauf zurückzuführen, dass PowerShell beim Konvertieren von Gleitkommazahlen in Ganzzahlen Rundungen anstelle von Kürzungen verwendet. Da die Aufgabe nur eine proportionale Stablänge erforderte, sollte dies jedoch in Ordnung sein.

Im Vergleich zu anderen Lösungen habe ich bei der Bestimmung der längsten Taktlänge einen etwas anderen Ansatz gewählt, indem ich einfach die höchste Länge ausprobiert und genommen habe, bei der keine Zeile länger als 80 Zeichen ist.

Eine erklärte ältere Version finden Sie hier .


Beeindruckend, scheint Powershell eine geeignete Umgebung zum Golfen zu sein. Ihr Ansatz unter Berücksichtigung der Stablänge ist genau das, was ich in der Spezifikation zu beschreiben versucht habe (nicht so brillant, gebe ich zu).
ChristopheD

1
@ChristopheD: Nach meiner Erfahrung (Anarchy Golf, einige Project Euler-Aufgaben und einige weitere Aufgaben nur zum Spaß) ist PowerShell normalerweise nur geringfügig schlechter als Ruby und oft mit Perl und Python verbunden oder besser als diese. Keine Übereinstimmung mit GolfScript. Aber soweit ich sehen kann, könnte dies die kürzeste Lösung sein, die die Stablängen korrekt berücksichtigt ;-)
Joey

Anscheinend hatte ich recht. Powershell kann es besser - viel besser! Bitte geben Sie eine erweiterte Version mit Kommentaren an.
Gabe

Johannes: Hast du es versucht -split("\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z]")? Für mich geht das.
Gabe

Vergessen Sie nicht, die Ausgabezeichenfolge zu interpolieren: "|$('_'*($w*$_.count/$x[0].count))| $($_.name) "(oder entfernen Sie das letzte Leerzeichen, da dies automatisch erfolgt). Und Sie können verwenden -split("(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z])+"), um ein paar mehr zu speichern, indem Sie Leerzeichen (oder Verwendung [-2..-23]) nicht einschließen .
Gabe

19

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

Update 1: Hurra ! Es ist ein Gleichstand mit der Lösung von JS Bangs . Ich kann mir keinen Weg mehr vorstellen, um zu reduzieren :)

Update 2: Spielte einen schmutzigen Golftrick. Geändert each, mapum 1 Zeichen zu speichern :)

Update 3: Geändert File.readzu IO.read+2. Array.group_bywar nicht sehr fruchtbar, geändert auf reduce+6. Nach dem unteren Gehäuse mit ist keine Prüfung ohne Berücksichtigung der Groß- und Kleinschreibung erforderlichdowncase in Regex +1 Berücksichtigung der Groß- und . Das Sortieren in absteigender Reihenfolge erfolgt einfach durch Negieren des Werts +6. Gesamteinsparungen +15

Update 4: [0]anstatt .first+3. (@ Shtééf)

Update 5: Variable lan Ort und Stelle erweitern, +1. Erweitern Sie die Variable san Ort und Stelle, +2. (@ Shtééf)

Update 6: Verwenden Sie für die erste Zeile +2 die Zeichenfolgenaddition anstelle der Interpolation. (@ Shtééf)

w=(IO.read($_).downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).reduce(Hash.new 0){|m,o|m[o]+=1;m}.sort_by{|k,v|-v}.take 22;m=76-w[0][0].size;puts' '+'_'*m;w.map{|x,f|puts"|#{'_'*(f*1.0/w[0][1]*m)}| #{x} "}

Update 7: Ich habe eine ganze Menge Hoopla durchlaufen, um die erste Iteration innerhalb der Schleife mithilfe von Instanzvariablen zu erkennen . Alles was ich habe ist +1, obwohl es vielleicht Potenzial gibt. Beibehaltung der vorherigen Version, da ich glaube, dass dies schwarze Magie ist. (@ 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} "}

Lesbare Version

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

Benutzen:

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

Ausgabe:

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

3
Ist "p" nicht eine Abkürzung für "Puts"? Das könnte ein paar rasieren.
Rfusca

1
Nett. Ihre Verwendung von scangab mir jedoch eine bessere Idee, so dass ich wieder weiterkam :).
JSB 3

2
Sie müssen die Balken so skalieren, dass das längste Wort plus Balken auf 80 Zeichen passt. Wie Brian vorgeschlagen hat, wird ein langes zweites Wort Ihr Programm unterbrechen.
Gabe

3
Ich frage mich, warum dies immer noch Stimmen sammelt. Die Lösung ist falsch (im allgemeinen Fall) und zwei kürzere Ruby-Lösungen sind jetzt hier.
Joey

1
Korrigieren Sie mich jetzt, wenn ich falsch liege, aber anstatt "downcase" zu verwenden, warum verwenden Sie nicht das REGEXP-Flag für Groß- und Kleinschreibung, das 6-7 Bytes spart, nicht wahr?
st0le

19

Python 2.x, latitudinarianer Ansatz = 227 183 Zeichen

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

Unter Berücksichtigung der Freiheit bei der Implementierung habe ich eine Zeichenfolgenverkettung erstellt, die alle zum Ausschluss angeforderten Wörter enthält ( the, and, of, to, a, i, it, in, or, is) - und außerdem die beiden berüchtigten "Wörter" sund taus dem Beispiel ausschließt - und den Ausschluss für an, for, he. Ich habe alle Verkettungen dieser Wörter gegen das Korpus der Wörter aus Alice, King James 'Bibel und der Jargon-Datei versucht, um festzustellen, ob es Wörter gibt, die von der Zeichenfolge falsch ausgeschlossen werden. Und so endete ich mit zwei Ausschlusszeichenfolgen: itheandtoforinisund andithetoforinis.

PS. von anderen Lösungen ausgeliehen, um den Code zu verkürzen.

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

Schimpfen

In Bezug auf zu ignorierende Wörter würde man denken, dass diese aus der Liste der am häufigsten verwendeten Wörter auf Englisch entnommen werden. Diese Liste hängt vom verwendeten Textkorpus ab . Gemäß einer der beliebtesten Listen ( 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 ), Top 10 Wörter sind:the be(am/are/is/was/were) to of and a in that have I

Die 10 besten Wörter aus dem Alice im Wunderland-Text sind the and to a of it she i you said
Die 10 besten Wörter aus der Jargon-Datei (v4.4.7)the a of to and in is that or for

Die Frage ist also, warum orin die Ignorierliste des Problems aufgenommen wurde, wo es ~ 30 in der Popularität ist, wenn das Wort that(8. am häufigsten verwendet) nicht ist. usw. usw. Daher glaube ich, dass die Ignorierliste dynamisch bereitgestellt werden sollte (oder weggelassen werden könnte).

Eine alternative Idee wäre einfach, die Top-10-Wörter aus dem Ergebnis zu überspringen - was die Lösung tatsächlich verkürzen würde (elementar - muss nur den 11. bis 32. Eintrag anzeigen).


Python 2.x, pünktlicher Ansatz = 277 243 Zeichen

Das im obigen Code gezeichnete Diagramm wird vereinfacht (wobei nur ein Zeichen für die Balken verwendet wird). Wenn man das Diagramm aus der Problembeschreibung (die nicht erforderlich war) genau reproduzieren möchte, wird dieser Code dies tun:

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

Ich habe ein Problem mit der etwas zufälligen Auswahl der 10 Wörter, die ausgeschlossen the, and, of, to, a, i, it, in, or, iswerden sollen, damit diese als Befehlszeilenparameter übergeben werden, wie folgt:
python WordFrequencyChart.py the and of to a i it in or is <"Alice's Adventures in Wonderland.txt"

Dies sind 213 Zeichen + 30, wenn wir die "ursprüngliche" Ignorierliste berücksichtigen, die über die Befehlszeile übergeben wurde = 243

PS. Der zweite Code "passt" auch die Länge aller oberen Wörter an, sodass keines von ihnen im entarteten Fall überläuft.

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

Bisher eine gute Lösung, obwohl die Wort-Ignorier-Liste (noch) nicht implementiert ist und die Balken im Moment etwas rudimentär sind.
ChristopheD

@ChristopheD: Es war da, aber es gab kein "Benutzerhandbuch". Gerade Bündel Text hinzugefügt
Nas Banov

Zu Ihrer Liste der Sprachen und Lösungen: Suchen Sie nach Lösungen, die eine Aufteilung \Woder \beine Regex-Verwendung verwenden, da diese höchstwahrscheinlich nicht den Spezifikationen entsprechen. Dies bedeutet, dass sie nicht auf Ziffern aufgeteilt werden oder _Stoppwörter nicht aus Zeichenfolgen entfernt werden wie the_foo_or123bar. Sie erscheinen möglicherweise nicht im Testtext, aber die Spezifikation ist in diesem Fall ziemlich klar.
Joey

Erstaunliche Arbeit Nas, ich habe einen Nachmittag damit verbracht, dies zu optimieren und nur eine Verbesserung gefunden. Sie können es auf 239 Zeichen sys.argvre.findall(r'\b(?!(?:the|and|.|of|to|i[tns]|or)\b)\w+',sys.stdin.read().lower())
reduzieren,

12

Haskell - 366 351 344 337 333 Zeichen

(Ein Zeilenumbruch wurde mainzur besseren Lesbarkeit hinzugefügt, und am Ende der letzten Zeile ist kein Zeilenumbruch erforderlich.)

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

Wie es funktioniert, lässt sich am besten anhand des Arguments interactrückwärts lesen :

  • map f Kleinbuchstaben, ersetzt alles andere durch Leerzeichen.
  • words Erzeugt eine Liste von Wörtern, wobei das trennende Leerzeichen gelöscht wird.
  • filter (notElem words "the and of to a i it in or is")verwirft alle Einträge mit verbotenen Wörtern.
  • group . sort sortiert die Wörter und gruppiert identische in Listen.
  • map h ordnet jede Liste identischer Wörter einem Tupel des Formulars zu (-frequency, word) .
  • take 22 . sort sortiert die Tupel nach absteigender Häufigkeit (der erste Tupeleintrag) und behält nur die ersten 22 Tupel bei.
  • b ordnet Tupel Balken zu (siehe unten).
  • a stellt die erste Zeile der Unterstriche voran, um den obersten Balken zu vervollständigen.
  • unlines verbindet alle diese Zeilen mit Zeilenumbrüchen.

Das Knifflige ist, die richtige Stablänge zu finden. Ich nahm an, dass nur Unterstriche zur Länge des Balkens zählen, also ||ein Balken mit der Länge Null. Die Funktion bordnet c xüber x, wo xdie Liste der Histogramme ist. Die gesamte Liste wird an übergeben c, so dass jeder Aufruf vonc den Skalierungsfaktor durch Aufrufen für sich selbst berechnen kann u. Auf diese Weise vermeide ich die Verwendung von Gleitkomma-Mathematik oder Rationalen, deren Konvertierungsfunktionen und -importe viele Zeichen verbrauchen würden.

Beachten Sie den Trick der Verwendung -frequency. Dadurch entfällt die Notwendigkeit, reversedie sortseit Sortierung (aufsteigend) -frequencywerden Orte der Worte mit der größten Frequenz zuerst. Später in der Funktion uwerden zwei -frequencyWerte multipliziert, wodurch die Negation aufgehoben wird.


Sehr gute Arbeit (würde positiv stimmen, aber heute keine Stimmen mehr mit all den tollen Antworten in diesem Thread).
ChristopheD

Dies schmerzt meine Augen auf eine Weise, die selbst beim Beschreiben schmerzhaft ist, aber ich habe viel von Haskell gelernt, indem ich es in lesbaren Code zurückentwickelt habe. Gut gemacht, Sir. :-)
Owen S.

Es ist eigentlich immer noch ziemlich idiomatisch, wenn auch nicht wirklich effizient. Die kurzen Namen lassen es viel schlimmer aussehen als es wirklich ist.
Thomas

@ Thomas: Das kannst du nochmal sagen. :-)
Owen S.

1
Kann das diveigentlich nicht bewegen ! Probieren Sie es aus - die Ausgabe ist falsch. Der Grund ist, dass das divvor dem *Verlieren die Präzision verliert.
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)}

Leider for([k,v]in z)scheint die Version aus der Rhino-Version nicht in SpiderMonkey funktionieren zu wollen und readFile()ist ein wenig einfacher als die Verwendung, readline()aber wenn wir auf 1.8 aufsteigen, können wir Funktionsabschlüsse verwenden, um ein paar weitere Zeilen zu schneiden.

Hinzufügen von Leerzeichen zur besseren Lesbarkeit:

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

Verwendung: js golf.js < input.txt

Ausgabe:

 _________________________________________________________________________ 
| _________________________________________________________________________ | sie
| _______________________________________________________________ | Sie
| ____________________________________________________________ | sagte
| ____________________________________________________ | Alice
| ______________________________________________ | war
| ___________________________________________ | Das
| ___________________________________ | wie
| ________________________________ | ihr
| _____________________________ | beim
| _____________________________ | mit
| ____________________________ | s
| ____________________________ | t
| __________________________ | auf
| _________________________ | alles
| _______________________ | Dies
| ______________________ | zum
| ______________________ | hätten
| ______________________ | aber
| _____________________ | Sein
| _____________________ | nicht
| ___________________ | Sie
| ___________________ | so

(Basisversion - behandelt Balkenbreiten nicht richtig)

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

Ich denke, meine Sortierlogik ist aus, aber ... ich weiß nicht. Brainfart behoben.

Minimiert (Missbrauch wird manchmal \nals interpretiert ;):

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

Ah, Sir. Ich glaube, das ist dein Handschuh. Lass dein zweites mit meinem sprechen.
dmckee --- Ex-Moderator Kätzchen

2
Übrigens - ich mag das i[tns]?bisschen. Sehr hinterhältig.
dmckee --- Ex-Moderator Kätzchen

@dmckee - gut gespielt, ich glaube nicht, dass ich deine 336 schlagen kann, genieße deine verdiente Gegenstimme :)
Matt

Sie können definitiv 336 schlagen ... Es ist ein Schnitt mit 23 Zeichen verfügbar - .replace(/[^\w ]/g, e).split(/\s+/).map(kann durch .replace(/\w+/g,dieselbe Funktion ersetzt werden und diese verwenden, die Sie .mapgetan haben ... Auch nicht sicher, ob Rhino function(a,b)b.c-a.canstelle Ihrer Sortierfunktion unterstützt (Spidermonkey tut dies), aber das wird rasieren {return }... b.c-a.cist eine bessere Sorte als a.c<b.cübrigens ... Bearbeiten einer Spidermonkey-Version unten mit diesen Änderungen
Gnarf

Ich habe meine SpiderMonkey-Version nach oben verschoben, da sie der Einschränkung für die Balkenbreite entspricht. Außerdem konnte ich in Ihrer Originalversion ein paar weitere Zeichen herausschneiden, indem ich einen negativen Lookahead-Regexp verwendete, um Wörter zu verweigern, die ein einzelnes Ersetzen zulassen (). und ein paar Ifs mit ?:großartiger Basis zum Arbeiten gespielt!
Gnarf

11

PHP CLI-Version (450 Zeichen)

Diese Lösung berücksichtigt die letzte Anforderung, die die meisten Puristen bewusst ignoriert haben. Das hat 170 Zeichen gekostet!

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

Minimiert:

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

Für Menschen lesbar:

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

?>

Ausgabe:

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

Wenn es ein langes Wort gibt, werden die Balken richtig eingestellt:

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

11

Python 3.1 - 245 229 Zeichen

Ich denke, Counter zu benutzen ist eine Art Betrug :) Ich habe gerade vor einer Woche darüber gelesen, also war dies die perfekte Gelegenheit, um zu sehen, wie es funktioniert.

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

Druckt aus:

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

Ein Teil des Codes wurde aus der AKX-Lösung "entlehnt".


Die erste Zeile fehlt. Und die Stablänge ist nicht korrekt.
Joey

in deinem Code scheint das open('!')von stdin zu lesen - auf welcher Version / welchem ​​Betriebssystem ist das? oder müssen Sie die Datei '!' benennen?
Nas Banov

Nennen Sie die Datei "!" :) Entschuldigung, das war ziemlich unklar, und ich hätte es erwähnen sollen.
Sam Dolan

11

Perl, 205 191 189 Zeichen / 205 Zeichen (vollständig implementiert)

Einige Teile wurden von den früheren Perl / Ruby-Einsendungen inspiriert, einige ähnliche Ideen wurden unabhängig voneinander gefunden, die anderen sind originell. Die kürzere Version enthält auch einige Dinge, die ich aus anderen Einsendungen gesehen / gelernt habe.

Original:

$k{$_}++for grep{$_!~/^(the|and|of|to|a|i|it|in|or|is)$/}map{lc=~/[a-z]+/g}<>;@t=sort{$k{$b}<=>$k{$a}}keys%k;$l=76-length$t[0];printf" %s
",'_'x$l;printf"|%s| $_
",'_'x int$k{$_}/$k{$t[0]}*$l for@t[0..21];

Neueste Version mit bis zu 191 Zeichen:

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

Neueste Version mit bis zu 189 Zeichen:

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

Diese Version (205 Zeichen) berücksichtigt die Zeilen mit Wörtern, die länger sind als die später gefundenen.

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

10

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

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

Alternative, vollständige Implementierung einschließlich angegebenem Verhalten (globales Balkenquetschen) für den pathologischen Fall, in dem das Sekundärwort sowohl beliebt als auch lang genug ist, um mit über 80 Zeichen kombiniert zu werden ( diese Implementierung umfasst 231 Zeichen ):

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

In der Spezifikation wurde nirgends angegeben, dass dies an STDOUT gehen musste, daher habe ich perl's warn () anstelle von print verwendet - vier Zeichen wurden dort gespeichert. Verwendete Karte anstelle von foreach, aber ich habe das Gefühl, dass der Split (join ()) noch weitere Einsparungen bringen könnte. Trotzdem habe ich es auf 203 gebracht - könnte darauf schlafen. Zumindest ist Perl jetzt unter der Zeichenanzahl "shell, grep, tr, grep, sort, uniq, sort, head, perl";)

PS: Reddit sagt "Hallo";)

Update: join () wurde zugunsten der Zuweisung und des impliziten skalaren Konvertierungs-Joins entfernt. Bitte beachten Sie auch, dass ich die optionale Regel "1-Buchstaben-Wörter ignorieren" genutzt habe, um 2 Zeichen zu entfernen. Denken Sie also daran, dass die Häufigkeit dies widerspiegelt.

Update 2: Zuweisung und impliziter Join ausgetauscht, um $ / zu töten und die Datei mit <> in einem Zug zu erhalten. Gleiche Größe, aber böser. Ausgetauscht, wenn (! $ Y) {} gegen $ y || {} &&, 1 weiteres Zeichen gespeichert => 201.

Update 3: Übernahm die Kontrolle über die frühzeitige Kleinschreibung (lc <>), indem lc aus dem Kartenblock verschoben wurde. - Beide regulären Ausdrücke wurden ausgetauscht, um die Option / i nicht mehr zu verwenden, da sie nicht mehr benötigt wird. Vertauschtes explizites bedingtes x? Y: z-Konstrukt für traditionelles Perlgolf || implizites bedingtes Konstrukt - /^...$/i?1:$x{$ } ++ für /^...$/||$x{$ } ++ Drei Zeichen gespeichert! => 198, durchbrach die 200er Barriere. Könnte bald schlafen ... vielleicht.

Update 4: Schlafentzug hat mich verrückt gemacht. Gut. Wahnsinniger. Als ich herausfand, dass dies nur normale Happy-Text-Dateien analysieren muss, gab ich es auf, wenn es eine Null erreicht. Zwei Zeichen gespeichert. Ersetzt "Länge" durch das 1-Zeichen kürzere (und viel mehr Golf) y /// c - Sie hören mich, GolfScript? Ich komme für Sie!!! Schluchzen

Update 5: Sleep Dep hat mich das 22row-Limit und das Limit für nachfolgende Zeilen vergessen lassen. Sichern Sie bis zu 208 mit den behandelten. Nicht schlecht, 13 Zeichen sind nicht das Ende der Welt. Spielte mit Perls Regex-Inline-Bewertung herum, hatte aber Probleme, sie zum Laufen zu bringen und Zeichen zu sparen ... lol. Das Beispiel wurde aktualisiert, um der aktuellen Ausgabe zu entsprechen.

Update 6: Nicht benötigte Klammern wurden entfernt, um (...) zu schützen, da die syntaktische Süßigkeit ++ es ermöglicht, sie glücklich gegen die zu schieben. Dank der Eingabe von Chas. Owens (erinnert mein müdes Gehirn) hat dort die Lösung für die Charakterklasse i [tns] gefunden. Zurück zu 203.

Update 7: Zweite Arbeit hinzugefügt, vollständige Implementierung der Spezifikationen (einschließlich des vollständigen Quetschverhaltens der Balken für sekundäre Langwörter anstelle der Kürzung, die die meisten Leute ausführen, basierend auf der ursprünglichen Spezifikation ohne den pathologischen Beispielfall).

Beispiele:

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

Alternative Implementierung im pathologischen Fallbeispiel:

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

Sie können durch Kollabieren des regex für die Stoppwörter verkürzen is|in|it|iin i[snt]?- und dann gibt es keinen Unterschied mit der optionalen Regel mehr. (Hm, ich hätte nie darüber nachgedacht, einem Perl-Typ zu sagen, wie man Regex macht: D) ​​- einziges Problem jetzt: Ich muss schauen, wie ich drei Bytes von meiner eigenen Lösung abschneiden kann, um wieder besser als Perl zu sein: - |
Joey

Ok, ignoriere einen Teil von dem, was ich vorher gesagt habe. Das Ignorieren von Wörtern aus einem Buchstaben ist in der Tat ein Byte kürzer als das Nichtbeachten.
Joey

Jedes Byte zählt;) Ich habe überlegt, den Newline-Trick auszuführen, aber ich dachte, es ist tatsächlich die gleiche Anzahl von Bytes, auch wenn es weniger druckbare Zeichen sind. Ich arbeite immer noch daran zu sehen, ob ich es noch etwas verkleinern kann :)
Syntaera

Na ja, die Fallnormalisierung hat mich auf 209 zurückgeworfen. Ich sehe nicht, was ich sonst noch schneiden könnte. Obwohl Powershell kann kürzer als Perl sein. ;-)
Joey

Ich sehe nicht, wo Sie die Ausgabe auf die obersten 22 Wörter beschränken oder wo Sie sicherstellen, dass ein langes zweites Wort nicht umbrochen wird.
Gabe

9

F #, 452 Zeichen

Unkompliziert: Holen Sie sich eine Folge avon Wortzahlpaaren , finden Sie den besten Multiplikator für die Wortzahl pro Spalte kund drucken Sie die Ergebnisse.

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

Beispiel (Ich habe andere Freq-Zählungen als Sie, unsicher warum):

% 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

Es stellte sich heraus, dass meine eigene Lösung in der Tat ein wenig anders war (aufgrund einer etwas anderen Spezifikation), die Lösungen entsprechen jetzt ;-)
ChristopheD

+1 für die bislang einzig korrekte Implementierung der
Balkenskalierung

2
(@Rotsor: Ironisch, da meine die älteste Lösung ist.)
Brian

Ich wette, Sie könnten es ein wenig verkürzen, indem Sie die Teilungs-, Karten- und Filterstufen zusammenführen. Ich würde auch erwarten, dass Sie nicht so viele floats brauchen würden .
Gabe

Sind Verschachtelungsfunktionen normalerweise nicht kürzer als die Verwendung des Pipeline-Operators |>?
Joey

8

Python 2.6, 347 Zeichen

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

Ausgabe:

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

1
Sie können die Zeile verlieren, bm=(76.-len(W[0][0]))/W[0][1]da Sie bm nur einmal verwenden (machen Sie die nächste Zeile U=lambda n:"_"*int(n*(76.-len(W[0][0]))/W[0][1]), rasieren Sie 5 Zeichen ab. Außerdem: Warum sollten Sie beim Code-Golfen einen 2-stelligen Variablennamen verwenden? ;-)
ChristopheD

In der letzten Zeile ist das Leerzeichen nach dem Druck nicht erforderlich, rasiert ein Zeichen ab
ChristopheD

1
Berücksichtigt man nicht den Fall, dass das zweithäufigste Wort sehr lang ist, oder?
Joey

@ChristopheD: Weil ich diesen Code etwas zu lange angestarrt habe. : P Guter Fang. @ Johannes: Das könnte auch behoben werden, ja. Ich bin mir nicht sicher, ob alle anderen Implementierungen dies getan haben, als ich dies geschrieben habe.
AKX

7

* SH (+ Wellung), partielle Lösung

Dies ist unvollständig, aber zum Teufel, hier ist die Worthäufigkeit, die die Hälfte des Problems in 192 Bytes zählt:

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

7

Gawk - 336 (ursprünglich 507) Zeichen

(nach dem Korrigieren der Ausgabeformatierung; Korrigieren der Kontraktionssache; Optimieren; erneutes Optimieren; Entfernen eines völlig unnötigen Sortierschritts; erneutes Optimieren; und noch einmal (hoppla, dieser hat die Formatierung gebrochen); noch mehr optimieren; Matts Herausforderung annehmen, die ich verzweifelt optimiere so mehr; fand einen anderen Ort, um ein paar zu retten, gab aber zwei zurück, um den Fehler in der Balkenlänge zu beheben)

Heh heh! Ich bin momentan der Herausforderung des [Matt] JavaScript] [1] -Lösungszählers voraus ! ;) und [AKXs Python] [2].

Das Problem scheint nach einer Sprache zu verlangen, die native assoziative Arrays implementiert, daher habe ich natürlich eine mit einer schrecklich mangelhaften Anzahl von Operatoren ausgewählt. Insbesondere können Sie die Reihenfolge, in der awk die Elemente einer Hash-Map anbietet, nicht steuern. Daher scanne ich wiederholt die gesamte Map, um das aktuell zahlreichste Element zu finden, es auszudrucken und aus dem Array zu löschen.

Es ist alles furchtbar ineffizient, mit all den Golfspielen, die ich gemacht habe, ist es auch ziemlich schrecklich geworden.

Minimiert:

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

Zeilenumbrüche dienen nur der Übersichtlichkeit: Sie sind nicht erforderlich und sollten nicht gezählt werden.


Ausgabe:

$ 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

Lesbar; 633 Zeichen (ursprünglich 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]
    }
}

Gute Arbeit, gut, dass Sie eine eingerückte / kommentierte Version hinzugefügt haben ;-)
ChristopheD

7

Common LISP, 670 Zeichen

Ich bin ein LISP-Neuling, und dies ist ein Versuch, eine Hash-Tabelle zum Zählen zu verwenden (also wahrscheinlich nicht die kompakteste Methode).

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

kann zum Beispiel mit ausgeführt werden cat alice.txt | clisp -C golf.lisp.

In lesbarer Form ist

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

Haben Sie versucht, ein benutzerdefiniertes Lesemakro zu installieren, um die Eingabegröße zu verringern?
Aaron

@ Aaron eigentlich war es für mich nicht trivial, auch nur das zum Laufen zu bringen ... :-) Für den eigentlichen Golf-Teil habe ich nur Ein-Buchstaben-Variablen verwendet und das ist alles. Abgesehen von der etwas hohen Ausführlichkeit, die CL für diese Skala von Problemen innewohnt ("verketten" 'string "," setf "oder" gethash "sind Killer ... in Python sind sie" + "," = "," [] "). ) Trotzdem fühlte ich mich viel schlimmer, als ich es selbst auf logischer Ebene erwartet hätte. In gewissem Sinne habe ich das Gefühl, dass Lisp in Ordnung ist, aber gewöhnliches Lisp ist so lala und das jenseits der Benennung (erneutes Lesen ist ein sehr unfairer Kommentar, da meine Erfahrung mit CL nahe Null ist).
6502

wahr. Schema würde das Golfen ein bisschen einfacher machen, mit dem einzigen Namespace. Anstatt überall einen String anzufügen, könnten Sie (letrec ((ein String-Append) (b gethash)) ... (ein "x" "yz") ...)
Aaron

6

C (828)

Es sieht sehr nach verschleiertem Code aus und verwendet glib für Zeichenfolge, Liste und Hash. Char count mit wc -msagt 828 . Einzelzeichen werden nicht berücksichtigt. Um die maximale Länge des Balkens zu berechnen, wird das längste mögliche Wort unter allen berücksichtigt, nicht nur die ersten 22. Ist dies eine Abweichung von der Spezifikation?

Es behandelt keine Fehler und gibt keinen verwendeten Speicher frei.

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

Zeilenumbrüche zählen zwar als Zeichen, Sie können jedoch alle Zeilen entfernen, die keine Präprozessoranweisungen sind. Für einen Golf würde ich es nicht als schlechte Übung betrachten, das Gedächtnis nicht freizugeben.
Stéphan Kochen

ok ... setze alles in eine Zeile (erwarte Preproc-Makros) und gib einen Vers, ohne mem freizugeben (und wenn zwei andere Leerzeichen entfernt sind ... kann eine kleine Verbesserung der "Verschleierung" vorgenommen werden, z *v=*v*(77-lw)/m. B. 929. .. aber ich denke, es kann in Ordnung sein, wenn ich nicht einen Weg finde, es viel kürzer zu machen)
ShinTakezou

Ich denke, Sie können zumindest die int cin die mainErklärung verschieben und mainist implizit int(wie alle untypisierten Argumente, afaik) : main(c){...}. Sie könnten wahrscheinlich auch einfach schreiben 0statt NULL.
Joey

Wenn Sie es tun ... wird natürlich eine Warnung mit -Walloder mit -std=c99Flagge ausgelöst ... aber ich nehme an, dass dies für einen Code-Golf sinnlos ist, oder?
ShinTakezou

uff, sorry für kurze Zeitänderungen, ... Ich sollte Without freeing memory stuff, it reaches 866 (removed some other unuseful space)zu etwas anderem wechseln , um die Leute nicht glauben zu lassen, dass der Unterschied zur Version mit freiem Speicher darin besteht: Jetzt hat die Version ohne freien Speicher eine Menge mehr "Verbesserungen".
ShinTakezou

6

Perl, 185 char

200 (leicht gebrochen) 199 197 195 193 187 185 Zeichen. Die letzten beiden Zeilenumbrüche sind von Bedeutung. Entspricht der Spezifikation.

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

In der ersten Zeile werden die Anzahl der gültigen Wörter geladen %X.

Die zweite Zeile berechnet den minimalen Skalierungsfaktor, sodass alle Ausgabezeilen <= 80 Zeichen sind.

Die dritte Zeile (enthält zwei Zeilenumbruchzeichen) erzeugt die Ausgabe.


Dadurch werden Stoppwörter nicht aus Zeichenfolgen wie "foo_the_bar" entfernt. Die Zeilenlänge ist auch eine zu lang (lesen Sie die Spezifikation erneut: "Balken + Leerzeichen + Wort + Leerzeichen <= 80 Zeichen")
Joey

5

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

  • Aktualisierungen vor dem ersten 742 : Verbesserter Regex, Entfernen überflüssiger parametrisierter Typen, Entfernen überflüssiger Leerzeichen.

  • Update 742> 744 Zeichen : Der Hack mit fester Länge wurde behoben. Es hängt nur vom 1. Wort ab, (noch) nicht von anderen Wörtern. Es wurden mehrere Stellen gefunden, an denen der Code \\sgekürzt werden konnte ( in Regex ersetzt durch und ArrayListersetzt durch Vector). Ich suche jetzt nach einem kurzen Weg, um die Commons IO-Abhängigkeit und das Lesen von stdin zu entfernen.

  • Update 744> 752 Zeichen : Ich habe die Commons-Abhängigkeit entfernt. Es liest jetzt von stdin. Fügen Sie den Text in stdin ein und drücken Sie Ctrl+Z, um das Ergebnis zu erhalten.

  • Update 752> 742 Zeichen : Ich habe publicein Leerzeichen entfernt und den Klassennamen 1 anstelle von 2 Zeichen gesetzt. Jetzt werden Wörter mit einem Buchstaben ignoriert.

  • Update 742> 714 Zeichen : Aktualisiert gemäß den Kommentaren von Carl: Redundante Zuweisung entfernt (742> 730), ersetzt m.containsKey(k)durch m.get(k)!=null(730> 728), Teilstring der Zeile (728> 714) eingeführt.

  • Update 714> 680 Zeichen : Aktualisiert gemäß den Kommentaren von Rotsor: Verbesserte Berechnung der Balkengröße, um unnötiges Casting zu entfernen, und verbessert split(), um unnötiges zu entfernen 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);}}

Lesbarere Version:

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

Ausgabe:

 _________________________________________________________________________
| _________________________________________________________________________ | sie
| _______________________________________________________________ | Sie
| ____________________________________________________________ | sagte
| _____________________________________________________ | Alice
| _______________________________________________ | war
| ___________________________________________ | Das
| ____________________________________ | wie
| ________________________________ | ihr
| _____________________________ | mit
| _____________________________ | beim
| __________________________ | auf
| __________________________ | alles
| _______________________ | Dies
| _______________________ | zum
| _______________________ | hätten
| _______________________ | aber
| ______________________ | Sein
| _____________________ | nicht
| ____________________ | Sie
| ____________________ | so
| ___________________ | sehr
| __________________ | Was

Es saugt ziemlich , dass Java nicht hat String#join()und Verschlüsse (noch) nicht .

Bearbeiten von Rotsor:

Ich habe einige Änderungen an Ihrer Lösung vorgenommen:

  • Liste durch einen String ersetzt []
  • Das Argument 'args' wurde wiederverwendet, anstatt mein eigenes String-Array zu deklarieren. Verwendet es auch als Argument für .ToArray ()
  • Ersetzte StringBuffer durch einen String (ja, ja, schreckliche Leistung)
  • Ersetzte die Java-Sortierung durch eine Auswahlsortierung mit frühem Anhalten (nur die ersten 22 Elemente müssen gefunden werden)
  • Aggregierte eine int-Deklaration zu einer einzigen Anweisung
  • Implementiert den Algorithmus ohne Betrug, der die einschränkendste Ausgabezeile findet. Implementiert ohne FP.
  • Das Problem, dass das Programm abstürzte, wenn der Text weniger als 22 verschiedene Wörter enthielt, wurde behoben
  • Implementierung eines neuen Algorithmus zum Lesen von Eingaben, der schnell und nur 9 Zeichen länger als der langsame ist.

Der komprimierte Code ist 688 711 684 Zeichen lang:

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

Die schnelle Version ( 720 693 Zeichen)

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

Lesbarere Version:

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

Die Version ohne Verhaltensverbesserungen besteht aus 615 Zeichen:

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

Könnten Sie nicht einfach den vollqualifizierten Namen verwenden, IOUtilsanstatt ihn zu importieren? Soweit ich sehen kann, verwenden Sie es sowieso nur einmal.
Joey

5
Sie haben betrogen, indem Sie davon ausgegangen sind, dass der längste Balken genau 75 Zeichen umfasst. Sie müssen sicherstellen, dass kein Balken + Wort länger als 80 Zeichen ist.
Gabe

Nach dem Wort fehlt ein Leerzeichen. ;)
st0le

Als ich meine Antwort reduzierte, hoffte ich, dass ich BalusCs Vorlage schlagen würde. Ich habe noch 200 Charaktere vor mir, ugh! Ich frage mich, wie lange dies ohne die Annahme von Commons IO & 75 char dauern würde.
Jonathon Faust

1
Sieht so aus, als könnten Sie einige Zeichen rasieren, indem Sie beinen String anstelle eines StringBuffers erstellen. Ich möchte jedoch nicht darüber nachdenken, wie die Leistung aussehen würde (zumal Sie jeweils einen Charakter hinzufügen).
Michael Myers

4

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

einschließlich Langworteinstellung. Ideen aus den anderen Lösungen entlehnt.

Jetzt als Skript ( 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)

Laufen Sie mit

scala -howtorun:script a.scala alice.txt

Übrigens entfernt die Bearbeitung von 314 auf 311 Zeichen tatsächlich nur 1 Zeichen. Jemand hat die Zählung vorher falsch verstanden (Windows CRs?).


4

Clojure 282 streng

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

Etwas leserlicher:

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

4

Scala, 368 Zeichen

Zunächst eine lesbare Version mit 592 Zeichen:

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

Die Konsolenausgabe sieht folgendermaßen aus:

$ 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

Wir können aggressiv minimieren und es auf 415 Zeichen reduzieren:

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

Die Konsolensitzung sieht folgendermaßen aus:

$ 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

Ich bin sicher, ein Scala-Experte könnte es noch besser machen.

Update: In den Kommentaren gab Thomas eine noch kürzere Version mit 368 Zeichen an:

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

Lesbar mit 375 Zeichen:

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

383 Zeichen: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

Natürlich immer griffbereit zum Verständnis! Nett!
pr1001

3

Java - 896 Zeichen

931 Zeichen

1233 Zeichen unlesbar gemacht

1977 Zeichen "unkomprimiert"


Update: Ich habe die Anzahl der Zeichen aggressiv reduziert. Lässt Wörter mit einem Buchstaben pro aktualisierter Spezifikation weg.

Ich beneide C # und LINQ so sehr.

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

"Lesbar":

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

Ausgabe von Alice:

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

Ausgabe von Don Quijote (ebenfalls aus Gutenberg):

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

8
Ganz Karpfen, gibt es wirklich keine Möglichkeit, es in Java kürzer zu machen? Ich hoffe ihr werdet nach Anzahl der Charaktere und nicht nach Funktionalität bezahlt :-)
Nas Banov
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.