小知识:Shell 词频统计

484 阅读3分钟

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

这个题目是leetcode的第192号题目。

题目是统计 words.txt 文件中每个单词的出现的频率。

词频统计是一个groupby操作,而我们在shell命令中并没有hash表可以供我们使用,如果要实现grouby自然要通过一个排序操作之后,再尝试分组操作。

而shell中为我们提供了一个这样的命令,也就是sort。

我们的流程应该是这样,通过sort得到有序的单词序列,然后再想办法给他分组(也就是相同的单词放在一起)。统计每个组中的单词的数量即可。

不过在此之前,还有一个问题,sort按行来排序,而单词文本并非一定是以行为单位分开的,更常见的情况是使用各种空白符甚至是逗号之类的分割符号。

不过在本题的环境下是以一个或多个空格分隔,姑且我们先考虑这样的情况。

一个很自然的想法就是替换文本,把这个用来分割的符号替换成换行。

那么我们可以在这里使用sed命令,使用它的正则表达式替换。像下面这样

sed -r 's#\s+#\n#g'

同样也可以用简单一点的命令tr ,把空格之类的压缩成一个换行

tr -s "[:blank:]" "\n"

除了这两个之外,还有个神奇的xargs也可以完成这个任务。

xargs是用来使用把输入的命令给其他命令当参数使用的。

默认情况下,他会把echo当成调用的命令。

而对于一堆参数,它还有可以设置每次传递多少个参数调用一次命令。那么只要我们让它每次调用命令只传递一个参数给echo。我们也可以同样实现空白符号转换成空格的操作。

xargs -n1 # 相当于是 xargs -n1 echo

文件转换成了可以使用sort排序的格式了,也就是说我们接下来我们要做的事是分组了。

很幸运的是shell中也有一个能一定程度上实现我们想要的分组的效果的命令: unique

在排序之后,我们可以使用uniq 去除重复的内容,并且在去重重复之后,我们还可以通过-c 参数输出每个去重之后的分组数量了。

uniq -c

其实到这里词频统计已经完成了。只不过leetcode上有额外的要求:以词频降序排列,然后词频需要写在每个单词的后面。

而现在uniq -c 的问题是顺序反了,且未按照排序要求输出。

因此我们的再通过两个额外的操作收尾。

首先是让输出以词频排序,现在词频是在第一列,sort通过指定-nr -k2以第二列的数值进行排序。

sort -nr -k2

为了让左右两列互换位置,我们可以使用强大的awk,让它把第一列和第二列反过来输出即可。

awk '{print $2,$1}'

到此为止我们有了这样一个管道命令

cat words.txt | tr -s "[:blank:]" "\n" | sort | uniq -c | sort -nr -k2 | awk '{print $2,$1}'

最后提交到力扣完成这个题目。

image.png