Scala 小技巧 - 单行代码完成word count

单行word count

Scala中可以一行命令就能做到word count的效果

假设有如下文本:

Hello mr apache spark

Hello world apache spark

Hello we want study spark

Hello we want study apache

Hello apache and hadoop



在scala终端中将数据存入list用以模拟

scala> var txt = List("Hello mr apache spark", "Hello world apache spark", "Hello we want study spark", "Hello we want study apache", "Hello apache and hadoop")
txt: List[String] = List(Hello mr apache spark, Hello world apache spark, Hello we want study spark, Hello we want study apache, Hello apache and hadoop)

我们的思路是什么?

1. 分词,得到一个list,存放了出现的所有单词

2. 对单词出现的次数做统计

3. 排序

1. 分词

首先我们将list进行map,对里面每一串文本,按照空格切分,得到一个list 里面存放的是多个数组,数组存放的是每个单词

scala> txt.map(_.split(" "))
res7: List[Array[String]] = List(Array(Hello, mr, apache, spark), Array(Hello, world, apache, spark), Array(Hello, we, want, study, spark), Array(Hello, we, want, study, apache), Array(Hello, apache, and, hadoop))

  

可以看到,得到的结果是 List[ Array[String]]    list里面的Array里面存放的就是一个个单词

但是我们不想要list 里面存放的是array, 想要list里面直接存放的就是单词,下面执行:

scala> txt.map(_.split(" ")).flatten
res8: List[String] = List(Hello, mr, apache, spark, Hello, world, apache, spark, Hello, we, want, study, spark, Hello, we, want, study, apache, Hello, apache, and, hadoop)

  

这样,就得到我们想要的样子。

其实上面两步操作,1 map  2 flatten 可以合并为一个操作,如下:

scala> txt.flatMap(_.split(" "))
res9: List[String] = List(Hello, mr, apache, spark, Hello, world, apache, spark, Hello, we, want, study, spark, Hello, we, want, study, apache, Hello, apache, and, hadoop)

  

2. 统计

在得到上述结果后就需要对单词出现的个数进行统计,怎么统计呢?

思路是,我们借鉴hadoop的mapper函数形式,对每一个单词都存入一个map(key value 集合)中,以单词为key,数字1为value:

scala> txt.flatMap(_.split(" ")).map((_, 1))
res10: List[(String, Int)] = List((Hello,1), (mr,1), (apache,1), (spark,1), (Hello,1), (world,1), (apache,1), (spark,1), (Hello,1), (we,1), (want,1), (study,1), (spark,1), (Hello,1), (we,1), (want,1), (study,1), (apache,1), (Hello,1), (apache,1), (and,1), (hadoop,1))

  

这样,我们就得到了一个list, list内存放的是一个个单独的map(元组,对偶元组)

然后,按照key进行group

scala> txt.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1)
res21: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(want -> List((want,1), (want,1)), world -> List((world,1)), hadoop -> List((hadoop,1)), spark -> List((spark,1), (spark,1), (spark,1)), apache -> List((apache,1), (apache,1), (apache,1), (apache,1)), Hello -> List((Hello,1), (Hello,1), (Hello,1), (Hello,1), (Hello,1)), mr -> List((mr,1)), we -> List((we,1), (we,1)), study -> List((study,1), (study,1)), and -> List((and,1)))

  

groupBy后得到一个map, key是单词, value是 一个list,list存放上一条执行的元组也就是 (单词, 1) 这个元组

实际上现在的这个map  key是单词, value这个list 的size 其实就是单词出现的次数了,所以我们要把value转换成出现的次数:

scala> txt.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).map( t => (t._1, t._2.size))
res2: scala.collection.immutable.Map[String,Int] = Map(want -> 2, world -> 1, hadoop -> 1, spark -> 3, apache -> 4, Hello -> 5, mr -> 1, we -> 2, study -> 2, and -> 1)

  

使用map方法,内用一个匿名函数,t 代表的就是上面map中的一个元素(key 单词,value 是list 的那个元素), 然后

函数的功能是 创建一个元组(map)key是单词, value就是原本元素value那个list 的size

这样得到了单词为key 次数为value的一个map

还有一种更为简洁的方法:

scala> txt.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.size)
res14: scala.collection.immutable.Map[String,Int] = Map(want -> 2, world -> 1, hadoop -> 1, spark -> 3, apache -> 4, Hello -> 5, mr -> 1, we -> 2, study -> 2, and -> 1)

  

3. 排序

txt.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).map( t => (t._1, t._2.size)).toList.sortBy(_._2)
res5: List[(String, Int)] = List((world,1), (hadoop,1), (mr,1), (and,1), (want,2), (we,2), (study,2), (spark,3), (apache,4), (Hello,5))

  

将得到的map(key 单词, value 次数)进行排序操作

由于map不支持sortBy函数,将map转换成list在执行sortBy

得到排序后的结果,但是我们要升序的,所以执行最后一步操作:

txt.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).map( t => (t._1, t._2.size)).toList.sortBy(_._2).reverse
res8: List[(String, Int)] = List((Hello,5), (apache,4), (spark,3), (study,2), (we,2), (want,2), (and,1), (mr,1), (hadoop,1), (world,1))

  

调用reverse方法反转即可

这样就得到了我们要的结果

所以总结就是:

txt.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).map( t => (t._1, t._2.size)).toList.sortBy(_._2).reverse

  

scala> txt.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.size).toList.sortBy(_._2).reverse
res18: List[(String, Int)] = List((Hello,5), (apache,4), (spark,3), (study,2), (we,2), (want,2), (and,1), (mr,1), (hadoop,1), (world,1))

  

打印出来看一看:

scala> txt.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).map( t => (t._1, t._2.size)).toList.sortBy(_._2).reverse.map(println)
(Hello,5)
(apache,4)
(spark,3)
(study,2)
(we,2)
(want,2)
(and,1)
(mr,1)
(hadoop,1)
(world,1)
res10: List[Unit] = List((), (), (), (), (), (), (), (), (), ())

  

或者:

scala> for( i <- txt.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.size).toList.sortBy(_._2).reverse) println(i)
(Hello,5)
(apache,4)
(spark,3)
(study,2)
(we,2)
(want,2)
(and,1)
(mr,1)
(hadoop,1)
(world,1)

  

欢迎转载,欢迎提出意见

如果本文对您有帮助,还请点击一下推荐哦,Thanks?(?ω?)?

https://www.cnblogs.com/bigdatacaoyu

原文地址:https://www.cnblogs.com/bigdatacaoyu/p/10925404.html

时间: 2024-10-08 00:02:12

Scala 小技巧 - 单行代码完成word count的相关文章

开发小技巧2——代码段

概念: 代码段是将预先定义好的可重用代码块快速插入到代码文件中,代码段提高了开发效率,增强了代码的可重用性:既节约了时间,又实现了不同开发人员间代码的共享.同时也可保证同一项目中代码风格的统一. Visual Studio中已经定义了部分代码段,例如:在visual studio中输入for按tab健即可自动生成for循环语句,输入tryf按tab则自动生成try catch语句.       在Visual Studio 2012中创建自定义代码段: 选中项目文件,右击添加-新建项-选择XML

Xcode小技巧:使用代码块+查看某行代码作者+运行时显示控件边框

1.如果使用 git 来开发,可以快速定位你现在看不懂的代码是哪个2货写的,然后即使把锅甩到他身上(ps:如果是自己写的,你就默不作声,别让别人知道这个技巧哈),其实就是 show blame for line. 2.有句话说的好,聪明的程序员懂得"偷懒"来提升开发效率.我们在日常开发中,有一些代码片段会经常利用到,大家可能会觉得定义一些宏可以解决问题,但是遇到比如,UITableView的协议方法,或者写Demo时候想要快速的定义一个UIButton(当然,你用storyboard除

#WordPress小技巧#纯代码为自己博客添加支付宝/微信打赏功能

原文:https://www.wn789.com/13323.html 很多人的WordPress博客在文章尾部都有打赏功能,让读者可以直接通过扫描微信.支付宝二维码进行赞助,毕竟维护博客,编写博文需要花费不少的精力,大多数朋友和蜗牛一样都是利用自己业余时间对博客进行管理与维护(如果大家觉得蜗牛789文章能起到一定帮助作用,也欢迎对蜗牛进行打赏,目前大家可以通过支付宝扫红包活动对蜗牛进行打赏,无需自己掏腰包#每日#支付宝扫码最高领取99元红包 可用于店面消费或捐赠蜗牛). 在此文章中蜗牛为大家分

scala 小技巧

1. scala 编程虽然类似于 python ,但也严格遵守Java的相关准则 .如导入类 , 依赖等 .并且可通用类库 . 其最好用的一点事对数据的类型转换更方便 结果是3600 , 转无数次也一样 ,虽然没必要 .但是在数据编程方面 , 会更方便. 这也是为什么Spark是用scala 开发. 因为涉及到转换次数更多, 只要合理,不需要过分考虑类型的问题. 2. 原文地址:https://www.cnblogs.com/alpha-cat/p/12529262.html

Android——隐藏输入法的小技巧

今天偶然在百度地图提供的DEMO里看到这样一段代码,觉得确实是个小技巧,就写下来分享一下. 针对的问题: 我们在开发android界面的时候,经常使用EditText控件,然后每次进入这个页面的时候,获取焦点,自动调用输入法.有时候我们并不需要这样,接下来就是这个小技巧的代码了,加入到这个布局第一个EditText之前即可: <!-- 隐藏输入法用 --> <LinearLayout android:layout_width="0px" android:layout_

技巧分享丨可以提高千倍效率的Java代码的35个小技巧

前言 代码优化 ,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是,吃的小虾米一多之后,鲸鱼就被喂饱了. 代码优化也是一样,如果项目着眼于尽快无BUG上线,那么此时可以抓大放小,代码的细节可以不精打细磨:但是如果有足够的时间开发.维护代码,这时候就必须考虑每个可以优化的细节了,一个一个细小的优化点累积起来,对于代码的运行效率绝对是有提升的. 代码优化的目标是

Android课程---Android Studio使用小技巧:提取方法代码片段

这篇文章主要介绍了Android Studio使用小技巧:提取方法代码片段,本文分享了一个快速复制粘贴方法代码片段的小技巧,并用GIF图演示,需要的朋友可以参考下 今天来给大家介绍一个非常有用的Studio Tips,有些时候我们在一个方法内部写了过多的代码,然后想要把一些代码提取出来再放在一个单独的方法里,通常我们的做法是复制粘贴,现在我来教给大家一个非常简洁的方法,先看下gif演示吧:

代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧

代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧 最近接触了几个刚入门的iOS学习者,他们之中存在一个普遍和困惑和疑问,就是应该如何制作UI界面.iOS应用是非常重视用户体验的,可以说绝大多数的应用成功与否与交互设计以及UI是否漂亮易用有着非常大的关系.而随着iOS开发发展至今,可以说在UI制作上大家逐渐分化为了三种主要流派:使用代码手写UI及布局:使用单个xib文件组织viewController或者view:使用StoryBoard来通过

git小技巧:git blame && git show 查看某一行代码的修改历史

先查看某行代码由谁写的,在哪个commit中提交的: git blame file_name git blame -L 58,100 KeyboardActivity.java 其显示格式为: commit ID | 代码提交作者 | 提交时间 | 代码位于文件中的行数 | 实际代码 类似于下面这样: 这样,我们就可以知道commit ID了,然后使用命令:Git show commitID来看~ git小技巧:git blame && git show 查看某一行代码的修改历史