在给定的文本中建立一个ASCII图表,显示最常用的单词。

156

挑战:

构建一个给定文本中最常用单词的ASCII图表。

规则:

  • 只接受a-zA-Z(字母字符)作为单词的一部分。
  • 忽略大小写(She == she,我们的目的是相同的)。
  • 忽略以下单词(相当武断,我知道):the, and, of, to, a, i, it, in, or, is
  • 澄清:考虑到don't:在a-zA-Z范围内,这将被视为2个不同的“单词”:(dont)。

  • 可选地(现在正式更改规格已经太晚了),您可以选择删除所有单个字母的“单词”(这可能会导致忽略列表缩短)。

解析给定的文本(通过命令行参数或管道读取指定的文件;假设为us-ascii),并构建一个以下特征的词频图表

  • 显示最常见的22个单词的图表(按降序排列)。
  • 条形宽度表示单词出现的次数(频率比例)。在单词后面添加一个空格并打印单词。
  • 确保这些条形图(加上空格-单词-空格)总是适合bar + [space] + word + [space]应始终<= 80个字符(确保您考虑可能不同的条形和单词长度:例如:第二个最常见的单词可能比第一个长得多,而在频率上并没有那么大的差异)。在这些约束条件下最大化条形宽度,并根据它们所代表的频率适当缩放条形。

示例:

示例文本 在这里找到《爱丽丝梦游仙境》,刘易斯·卡罗尔著)。

此特定文本将产生以下图表:

 _________________________________________________________________________
|_________________________________________________________________________| 她 
|_______________________________________________________________| 你 
|____________________________________________________________| 说 
|____________________________________________________| 爱丽丝 
|______________________________________________| 是 
|__________________________________________| 那个 
|___________________________________| 如同 
|_______________________________| 她的 
|____________________________| 和 
|____________________________| 在 
|___________________________| 的 
|___________________________| 特 
|_________________________| 定 
|_________________________| 所有 
|______________________| 这个 
|______________________| 对于 
|______________________| 有 
|_____________________| 但是 
|____________________| 是 
|____________________| 不 
|___________________| 他们 
|__________________| 这么

供您参考:上述图表所建立的频率如下:

与编程相关的内容:
将链接的《爱丽丝梦游仙境》文件中每个“you”替换为“superlongstringstring”:
[('她', 553), ('你', 481), ('说', 462), ('爱丽丝', 403), ('是', 358), ('那', 330), ('作为', 274), ('她的', 248), ('与', 227), ('在', 227), ('s', 219), ('t', 218), ('上', 204), ('所有', 200), ('这', 181), ('为', 179), ('有', 178), ('但', 175), ('是', 167), ('不', 166), ('他们', 155), ('如此', 152)]
获胜者:

最短的解决方案(按每种语言的字符计数)。祝玩得愉快!


编辑:总结到目前为止的结果表(2012-02-15)(最初由用户Nas Banov添加):

语言               宽松     严格
=========         =======  ======
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

这些数字代表特定语言中最短解决方案的长度。“严格”是指实现了规范的解决方案(绘制|____|条,用一条____线在顶部关闭第一个条,考虑具有高频率的长单词等)。"宽松"意味着采取了某些自由以缩短解决方案。

仅包含长度小于500个字符的解决方案。语言列表按“严格”解决方案的长度排序。“Unix工具链”用于表示使用传统*nix shell 加上一些工具(如grep、tr、sort、uniq、head、perl、awk)的各种解决方案。


4
“最长的酒吧”加上一个单词可能达不到80个字符,如果第二常见的单词比较长的话。我想我在寻找“最大约束”。 - Brian
2
在我看来,让这个程序在执行时间和内存使用方面都表现出色,似乎比字符计数更具有挑战性。 - Frank Farmer
81
很高兴看到我最喜欢的词 st 得到了体现。 - indiv
1
@Frank,是的,但那样就不算代码高尔夫了。 - JSBձոգչ
8
@indiv,@Nas Banov -- 简单得有些傻的分词器会把"didn't" 分成 {didn, t},把 "she's" 分成 {she, s} :) - hobbs
显示剩余29条评论
59个回答

122

LabVIEW 51个节点,5种结构,10张图表

教大象跳探戈从未容易过。我会跳过字符计数。

labVIEW 代码

结果

程序从左向右流动:

labVIEW 代码解释


10
不值得。 - user216441
4
LabVIEW在硬件控制和测量领域非常得心应手,但在字符串操作方面却非常糟糕。 - Joe Z
19
我见过的最佳代码高尔夫答案。 +1 因为别具一格! - Blair Holloway
1
得为我们计算元素数量...每个你必须拖到屏幕上的框和小部件都要算在内。 - dmckee --- ex-moderator kitten
1
是否可以添加一个链接到那些图表的更大版本? - Svish
显示剩余5条评论

42

Ruby 1.9,185个字符

(在其他Ruby解决方案的基础上进行了大量修改)

w=($<.read.downcase.scan(/[a-z]+/)-%w{the and of to a i it in or is}).group_by{|x|x}.map{|x,y|[-y.size,x]}.sort[0,22]
k,l=w[0]
puts [?\s+?_*m=76-l.size,w.map{|f,x|?|+?_*(f*m/k)+"| "+x}]

与其他解决方案不同,您可以简单地将文件名作为参数传递(即ruby1.9 wordfrequency.rb Alice.txt),而无需使用任何命令行开关。

由于我在这里使用了字符文字,因此此解决方案仅适用于Ruby 1.9。

编辑:为了“可读性”,将分号替换为换行符。:P

编辑2:Shtééf指出我忘记了尾随空格 - 已修正。

编辑3:再次删除尾随空格;)


每个单词后面都缺少尾随空格。 - Stéphan Kochen
哎呀,不好意思。看起来高尔夫球刚刚更新了,不再需要尾随空格了。 :) - Stéphan Kochen
似乎没有考虑到第二个或之后的位置出现“超长字符串”?(请参见问题描述) - Nas Banov
2
那看起来真的很易于维护。 - Zombies

39

GolfScript,177 175 173 167 164 163 144 131 130 字符

较慢 - 样例文本(130)需要 3 分钟。

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

解释:

{           #loop through all characters
 32|.       #convert to uppercase and duplicate
 123%97<    #determine if is a letter
 n@if       #return either the letter or a newline
}%          #return an array (of ints)
]''*        #convert array to a string with magic
n%          #split on newline, removing blanks (stack is an array of words now)
"oftoitinorisa"   #push this string
2/          #split into groups of two, i.e. ["of" "to" "it" "in" "or" "is" "a"]
-           #remove any occurrences from the text
"theandi"3/-#remove "the", "and", and "i"
$           #sort the array of words
(1@         #takes the first word in the array, pushes a 1, reorders stack
            #the 1 is the current number of occurrences of the first word
{           #loop through the array
 .3$>1{;)}if#increment the count or push the next word and a 1
}/
]2/         #gather stack into an array and split into groups of 2
{~~\;}$     #sort by the latter element - the count of occurrences of each word
22<         #take the first 22 elements
.0=~:2;     #store the highest count
,76\-:1     #store the length of the first line
'_':0*' '\@ #make the first line
{           #loop through each word
"
|"\~        #start drawing the bar
1*2/0       #divide by zero
*'| '@      #finish drawing the bar
}/

"正确"(希望如此)。 (143)

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

更快 - 少了一半时间。 (162)

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

输出可见于版本记录。


2
关于GolfScript:http://www.golfscript.com/golfscript/ - Assaf Lavie
2
不正确,如果第二个单词非常长,它将换到下一行。 - Gabe
5
“除以零”的意思是什么?GolfScript允许这样做吗? - JAB

35

206

使用shell中的grep、tr、sort、uniq、head和perl命令。

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

哦,刚刚看到上面的代码:sort -nr -> sort -n 然后 head -> tail => 208 :)
更新2:嗯,当然上面的做法是愚蠢的,因为这样会得到反向的结果。所以得到了209。
更新3:优化了排除正则表达式 -> 206

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



为了好玩,这里有一个仅使用Perl的版本(速度更快):

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

35

基于集合的Transact SQL解决方案(SQL Server 2005)1063 892 873 853 827 820 783 683 647 644,共630个字符。

感谢Gabe提供了一些有用的建议来减少字符数量。

注:添加换行符只是为了避免滚动条,只需保留最后一个换行符即可。

DECLARE @ VARCHAR(MAX),@F REAL SELECT @=BulkColumn FROM OPENROWSET(BULK'A',
SINGLE_BLOB)x;WITH N AS(SELECT 1 i,LEFT(@,1)L UNION ALL SELECT i+1,SUBSTRING
(@,i+1,1)FROM N WHERE i<LEN(@))SELECT i,L,i-RANK()OVER(ORDER BY i)R INTO #D
FROM N WHERE L LIKE'[A-Z]'OPTION(MAXRECURSION 0)SELECT TOP 22 W,-COUNT(*)C
INTO # FROM(SELECT DISTINCT R,(SELECT''+L FROM #D WHERE R=b.R FOR XML PATH
(''))W FROM #D b)t WHERE LEN(W)>1 AND W NOT IN('the','and','of','to','it',
'in','or','is')GROUP BY W ORDER BY C SELECT @F=MIN(($76-LEN(W))/-C),@=' '+
REPLICATE('_',-MIN(C)*@F)+' 'FROM # SELECT @=@+' 
|'+REPLICATE('_',-C*@F)+'| '+W FROM # ORDER BY C PRINT @

易读版本

DECLARE @  VARCHAR(MAX),
        @F REAL
SELECT @=BulkColumn
FROM   OPENROWSET(BULK'A',SINGLE_BLOB)x; /*  Loads text file from path
                                             C:\WINDOWS\system32\A  */

/*Recursive common table expression to
generate a table of numbers from 1 to string length
(and associated characters)*/
WITH N AS
     (SELECT 1 i,
             LEFT(@,1)L

     UNION ALL

     SELECT i+1,
            SUBSTRING(@,i+1,1)
     FROM   N
     WHERE  i<LEN(@)
     )
  SELECT   i,
           L,
           i-RANK()OVER(ORDER BY i)R
           /*Will group characters
           from the same word together*/
  INTO     #D
  FROM     N
  WHERE    L LIKE'[A-Z]'OPTION(MAXRECURSION 0)
             /*Assuming case insensitive accent sensitive collation*/

SELECT   TOP 22 W,
         -COUNT(*)C
INTO     #
FROM     (SELECT DISTINCT R,
                          (SELECT ''+L
                          FROM    #D
                          WHERE   R=b.R FOR XML PATH('')
                          )W
                          /*Reconstitute the word from the characters*/
         FROM             #D b
         )
         T
WHERE    LEN(W)>1
AND      W NOT IN('the',
                  'and',
                  'of' ,
                  'to' ,
                  'it' ,
                  'in' ,
                  'or' ,
                  'is')
GROUP BY W
ORDER BY C

/*Just noticed this looks risky as it relies on the order of evaluation of the 
 variables. I'm not sure that's guaranteed but it works on my machine :-) */
SELECT @F=MIN(($76-LEN(W))/-C),
       @ =' '      +REPLICATE('_',-MIN(C)*@F)+' '
FROM   #

SELECT @=@+' 
|'+REPLICATE('_',-C*@F)+'| '+W
             FROM     #
             ORDER BY C

PRINT @

输出

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

使用长字符串时

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

12
我给你点赞是因为你用T-SQL做到了,并引用《美国队长》的经典语录"你很有胆量,我喜欢有胆量的人。" - user174624
3
那段代码让我感到焦虑!:O - Joey
1
一个良好的节省方式是将 0.000 更改为 0,然后使用 -C 代替 1.0/C。而且将 FLOAT 修改为 REAL 也可以省去一些打字。不过最重要的是,你似乎有很多应该是可选的 AS 实例。 - Gabe
1
好的,那么SELECT [ ] FROM (SELECT $0 O, ' '+REPLICATE('_', MAX(C)*@F)+' ' [ ] FROM # UNION SELECT $1/C, '|'+REPLICATE('_',C*@F)+'| '+W FROM #)X ORDER BY O怎么样? - Gabe
@Gabe 我喜欢你和Martin的二重唱。我冒险尝试缩短它(另一个答案)- 我觉得CTE看起来有点长。 - RichardTheKiwi
显示剩余9条评论

34

Ruby 200 chars

这是Anurag的改进版本,结合了rfusca的建议。还删除了排序参数和其他一些小优化。

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

以以下方式执行:

ruby GolfedWordFrequencies.rb < Alice.txt

编辑:将'puts'放回,需要它才能避免输出中出现引号。
编辑2:更改File->IO。
编辑3:删除/i。
编辑4:移除(f*1.0)周围的括号,重新计数。
编辑5:对于第一行使用字符串拼接;对s进行原地扩展。
编辑6:将m变为浮点数,去掉1.0。编辑:不起作用,会改变长度。编辑:与之前相比没有变得更糟。
编辑7:使用STDIN.read


+1 - 爱那个排序部分,非常聪明 :) - Anurag
解决方案与原始输出不一致,我将尝试找出发生了什么。 - archgoon
@archgoon:我赞扬你的高尚努力,但字符串相加并不比循环更短。它只是因为你去掉了尾随空格而变得更短。但不要感到难过,这并不能让Perl看起来更好。;) - Stéphan Kochen
用 [0..21] 代替 .take 22 怎么样? - Dogbert
1
这个有更短的变体在下面。 - archgoon
显示剩余4条评论

28

Mathematica (199字符)纯函数化

以及Zipf定律测试

看,妈妈……没有变量,没有手,没有头

编辑1>定义了一些简写(284字符)

f[x_, y_] := Flatten[Take[x, All, y]]; 

BarChart[f[{##}, -1], 
         BarOrigin -> Left, 
         ChartLabels -> Placed[f[{##}, 1], After], 
         Axes -> None
] 
& @@
Take[
  SortBy[
     Tally[
       Select[
        StringSplit[ToLowerCase[Import[i]], RegularExpression["\\W+"]], 
       !MemberQ[{"the", "and", "of", "to", "a", "i", "it", "in", "or","is"}, #]&]
     ], 
  Last], 
-22]

一些解释

Import[] 
   # Get The File

ToLowerCase []
   # To Lower Case :)

StringSplit[ STRING , RegularExpression["\\W+"]]
   # Split By Words, getting a LIST

Select[ LIST, !MemberQ[{LIST_TO_AVOID}, #]&]
   #  Select from LIST except those words in LIST_TO_AVOID
   #  Note that !MemberQ[{LIST_TO_AVOID}, #]& is a FUNCTION for the test

Tally[LIST]
   # Get the LIST {word,word,..} 
     and produce another  {{word,counter},{word,counter}...}

SortBy[ LIST ,Last]
   # Get the list produced bt tally and sort by counters
     Note that counters are the LAST element of {word,counter}

Take[ LIST ,-22]
   # Once sorted, get the biggest 22 counters

BarChart[f[{##}, -1], ChartLabels -> Placed[f[{##}, 1], After]] &@@ LIST
   # Get the list produced by Take as input and produce a bar chart

f[x_, y_] := Flatten[Take[x, All, y]]
   # Auxiliary to get the list of the first or second element of lists of lists x_
     dependending upon y
   # So f[{##}, -1] is the list of counters
   # and f[{##}, 1] is the list of words (labels for the chart)

输出

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

Mathematica不适合用于golfing,这只是因为函数名太长而且有描述性。像"RegularExpression[]"或"StringSplit[]"这样的函数让我感到难过:(。

Zipf定律测试

Zipf定律预测自然语言文本中Log(Rank)Log(occurrences)的关系应该线性

该定律用于开发加密和数据压缩算法(但它不是LZW算法中的“Z”)。

在我们的文本中,可以使用以下内容进行测试

 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]
结果几乎是线性的。 alt文本 http://i46.tinypic.com/33fcmdk.jpg 编辑6> (242字符)
重构正则表达式(不再使用Select函数) 删除一个字符的单词 对函数“f”进行更有效的定义
f = Flatten[Take[#1, All, #2]]&; 
BarChart[
     f[{##}, -1], 
     BarOrigin -> Left, 
     ChartLabels -> Placed[f[{##}, 1], After], 
     Axes -> None] 
& @@
  Take[
    SortBy[
       Tally[
         StringSplit[ToLowerCase[Import[i]], 
          RegularExpression["(\\W|\\b(.|the|and|of|to|i[tns]|or)\\b)+"]]
       ],
    Last],
  -22]

编辑7→199个字符

BarChart[#2, BarOrigin->Left, ChartLabels->Placed[#1, After], Axes->None]&@@ 
  Transpose@Take[SortBy[Tally@StringSplit[ToLowerCase@Import@i, 
    RegularExpression@"(\\W|\\b(.|the|and|of|to|i[tns]|or)\\b)+"],Last], -22]
  • Transpose替换f,并使用Slot (#1/#2)参数。
  • 如果可能的话,不需要使用括号(使用f@x代替f[x])

9
你认为"RegularExpression"很糟糕?当我在C#版本中键入"System.Text.RegularExpressions.Regex.Split"时,我曾哭泣,直到我看到了Objective-C代码:"stringWithContentsOfFile"、"enumerateSubstringsInRange"、"NSStringEnumerationByWords"、"sortedArrayUsingComparator"等等。 - Gabe
2
@Gabe 谢谢...我现在感觉好多了。在西班牙语中,我们说“mal de muchos, consuelo de tontos”..意思是“许多人烦恼,傻瓜得到安慰” :D - Dr. belisarius
1
你的正则表达式中的 |i| 是多余的,因为你已经有了 .| - Gabe
1
我喜欢那个西班牙谚语。我能想到的最接近英语的说法是“同病相怜”。这是我的翻译尝试:“当遭受苦难时,寻求同病相怜只会让自己变得愚蠢。”顺便说一下,Mathematica实现方面的工作真是太棒了。 - dreeves
@Johannes Rössel 很敏锐!由于Mathematica将下划线匹配为字母字符(他们为什么要这样做??!!),所以所有版本都存在此错误。正则表达式应该类似于“(_|\W|\b(.|the|and|of|to|i[tns]|or)\b)+”,但\W也将数字识别为字母,因此可能需要更长的完全正确版本。 - Dr. belisarius
显示剩余4条评论

26

C# - 422个字符(经过压缩)

虽然不算特别短,但现在应该是正确的了!请注意,以前的版本没有显示条形图的第一行,没有正确地缩放条形图,下载了文件而不是从stdin获取文件,并且没有包含所有必需的C#冗长代码。如果C#不需要那么多额外的东西,你可以很容易地减少许多字符数。也许PowerShell可以做得更好。

using C=System.Console;   // alias for Console
using System.Linq;  // for Split, GroupBy, Select, OrderBy, etc.

class Class // must define a class
{
    static void Main()  // must define a Main
    {
        // split into words
        var allwords = System.Text.RegularExpressions.Regex.Split(
                // convert stdin to lowercase
                C.In.ReadToEnd().ToLower(),
                // eliminate stopwords and non-letters
                @"(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|\W)+")
            .GroupBy(x => x)    // group by words
            .OrderBy(x => -x.Count()) // sort descending by count
            .Take(22);   // take first 22 words

        // compute length of longest bar + word
        var lendivisor = allwords.Max(y => y.Count() / (76.0 - y.Key.Length));

        // prepare text to print
        var toPrint = allwords.Select(x=> 
            new { 
                // remember bar pseudographics (will be used in two places)
                Bar = new string('_',(int)(x.Count()/lendivisor)), 
                Word=x.Key 
            })
            .ToList();  // convert to list so we can index into it

        // print top of first bar
        C.WriteLine(" " + toPrint[0].Bar);
        toPrint.ForEach(x =>  // for each word, print its bar and the word
            C.WriteLine("|" + x.Bar + "| " + x.Word));
    }
}

以下表格中有422个字符,其中包含了lendivisor(这使得它的速度变慢了22倍)。请注意,下面的格式中使用了换行符来表示空格。
using System.Linq;using C=System.Console;class M{static void Main(){var
a=System.Text.RegularExpressions.Regex.Split(C.In.ReadToEnd().ToLower(),@"(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|\W)+").GroupBy(x=>x).OrderBy(x=>-x.Count()).Take(22);var
b=a.Select(x=>new{p=new string('_',(int)(x.Count()/a.Max(y=>y.Count()/(76d-y.Key.Length)))),t=x.Key}).ToList();C.WriteLine(" "+b[0].p);b.ForEach(x=>C.WriteLine("|"+x.p+"| "+x.t));}}

+1 对于那些聪明地在内联下载文件的人。 :) - sarnold
1
从Matt的回答中获取短网址。 - indiv
2
规范要求文件必须通过管道或作为参数传递。如果你假设args[0]包含本地文件名,那么你可以使用args[0]代替(new WebClient()).DownloadString(@"http://www.gutenberg.org/files/11/11.txt")来缩短代码,这将节省大约70个字符。 - thorkia
1
下面是一个版本,将WebClient的调用替换为args 0的StreamReader调用,并删除了一些额外的空格。总字符数=413 var a = Regex.Replace((new StreamReader(args [0])).ReadToEnd(), "[^a-zA-Z]", " ").ToLower().Split(' ').Where(x =>! (new[]{"the","and","of","to","a","i","it","in","or","is"}).Contains(x)).GroupBy(x=>x).Select(g=>new{w=g.Key,c=g.Count()}).OrderByDescending(x=>x.c).Skip(1).Take(22).ToList(); var m = a.OrderByDescending(x=>x.c).First(); a.ForEach(x=>Console.WriteLine("|"+new String('_',x.c*(80-m.w.Length-4)/m.c)+"| "+x.w)); - thorkia
条形图的宽度不正确。"with"的条形比"at"的短。 - Rotsor
显示剩余5条评论

25

Perl, 237 229 209 字符

(用更多的“肮脏高尔夫球技巧”更新,将split/[^a-z/,lc替换为lc=~/[a-z]+/g,并在另一个地方消除了对空字符串的检查。这些灵感来自Ruby版本,所以应该给予认可。)

更新:现已支持 Perl 5.10!将print替换为say,并使用~~来避免map。必须在命令行上调用此脚本,如perl -E '<one-liner>' alice.txt。由于整个脚本都在一行上,因此将其编写为单行代码不应该有任何困难:)。

 @s=qw/the and of to a i it in or is/;$c{$_}++foreach grep{!($_~~@s)}map{lc=~/[a-z]+/g}<>;@s=sort{$c{$b}<=>$c{$a}}keys%c;$f=76-length$s[0];say" "."_"x$f;say"|"."_"x($c{$_}/$c{$s[0]}*$f)."| $_ "foreach@s[0..21];

请注意,此版本对大小写进行了规范化。这并未缩短解决方案的长度,因为如果要删除lc(用于小写),则需要向分割正则表达式添加A-Z,所以这是一个折中。

如果您在一个换行符只有一个字符而不是两个字符的系统上,则可以通过使用文字换行符代替\n再缩短两个字符。但是,我没有按照上面的示例编写代码,因为那样更加“清晰”(哈!)。


以下是一个几乎正确但远远不够简短的Perl解决方案:

use strict;
use warnings;

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

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

print " " . ("_" x $widest) . "\n";
foreach (@sorted)
{
    my $width = int(($count{$_} / $count{$sorted[0]}) * $widest);
    print "|" . ("_" x $width) . "| $_ \n";
}
以下是尽可能短而又相对易读的代码(392字符)。
%short = map { $_ => 1 } qw/the and of to a i it in or is/;
%count;

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

print " " . "_" x $widest . "\n";
print"|" . "_" x int(($count{$_} / $count{$sorted[0]}) * $widest) . "| $_ \n" foreach @sorted;

目前有一些错误,正在修复和缩短。 - JSBձոգչ
4
这不包括第二个单词比第一个单词长得多的情况,对吗? - Joey
1
两个 foreach 可以写成 for。这样就减少了 8 个字符。然后你有 grep{!($_~~@s)}map{lc=~/[a-z]+/g}<>,我相信可以写成 grep{!(/$_/i~~@s)}<>=~/[a-z]+/g 来再减少 4 个字符。将 " " 替换为 $",又可以再减少 1 个字符... - Zaid
sort{$c{$b}-$c{$a}}... 可以再节省两个字。你也可以直接传递 %c 而不是 keys %csort 函数,这样可以再节省四个字。 - mob

20

Windows PowerShell,199个字符

$x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *
filter f($w){' '+'_'*$w
$x[-1..-22]|%{"|$('_'*($w*$_.Count/$x[-1].Count))| "+$_.Name}}
f(76..1|?{!((f $_)-match'.'*80)})[0]

最后一个换行符不是必要的,但为了易读性包含在这里。

(当前代码和我的测试文件可在我的SVN存储库中找到。我希望我的测试用例能捕捉到大多数常见错误(如长度、正则表达式匹配问题以及其他一些问题))

假设:

  • 输入为US ASCII。它可能在Unicode下变得奇怪。
  • 文本中至少有两个非停顿词

历史记录

松散版本(137),因为现在显然是单独计算的。

($x=$input-split'\P{L}'-notmatch'^(the|and|of|to|.?|i[tns]|or)$'|group|sort *)[-1..-22]|%{"|$('_'*(76*$_.Count/$x[-1].Count))| "+$_.Name}
  • 没有关闭第一个 bar 标签
  • 没有���虑到非第一个单词的长度

与其他解决方案相比,一字符长度的条形图差异是由于 PowerShell 在将浮点数转换为整数时使用四舍五入而不是截断。由于任务只需要比例条长,所以这应该没问题。

与其他解决方案相比,我采用了略微不同的方法来确定最长的条形图长度,即通过简单尝试并选择最高的长度,在此长度下没有任何行超过 80 个字符。

旧版本的说明可以在此处找到。


令人印象深刻,看来Powershell是适合高尔夫比赛的环境。您考虑酒吧长度的方法正是我在规范中试图描述(我承认不是很出色)的方法。 - ChristopheD
1
根据我的经验(Anarchy Golf,一些Project Euler任务以及一些只是为了好玩的任务),PowerShell通常只比Ruby稍差,并且经常与Perl和Python并列或更好。但是对于GolfScript来说,没有对手。但就我所看到的,这可能是正确计算条形码长度的最短解决方案;-) - Joey
不要忘记插入输出字符串:"|$('_'*($w*$_.count/$x[0].count))| $($_.name) "(或删除最后一个空格,因为它有点自动化)。你可以使用-split("(?:\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z])+") 来节省更多的空间,因为它不包括空格(或使用 [-2..-23]). - Gabe
请注意,如果没有尾随空格,则需要匹配 .{80}。并且您可以保证空格始终像这样排在第一位:"\b(?:the|and|of|to|a|i[tns]?|or)\b|[^a-z]()"(空捕获组确保每个单词都有一个空格)。 - Gabe
@Gabe:太好了,谢谢你。在functionfilter之间的比较上面,你很聪明地指出了它们之间的差异。我一开始考虑使用filter,只是没想到过滤器也可以带参数。对于我来说,这涉及到函数中的循环问题,因此不能将参数作为$_。这是一个不错的记忆技巧,谢谢:-)。不过,我认为这种方法现在已经被压缩到了极限。[我注意到我们在某个地方破坏了它......我的其他两个测试用例不再运行 - 正在调试……] - Joey
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接