Scala语言实现WordCount案例以及几个高级函数的使用总结

实现案例前需要熟悉scala中集合的几个高级函数:

  1. 映射:集合.map() 即拿到集合中元素做某些处理,返回当前集合的类型。
  2. 扁平化:集合.flatten() 就是提取外层集合中的内层集合中的元素,打散放入到外层集合中。
  3. 映射和扁平化可以写成一个函数:集合.flatMap()。
  4. 分组:集合.groupBy()函数:根据集合中元素的某个特征进行分组,返回值类型:Map(any -> List[any])
  5. 排序:一般List.sorted() 、List.sortBy()、 List.sortWith() ; List.sorted: 可以不指定参数,会按照集合中的元素进行自然排序。List.sortBy()():参数为函数类型:需传入一个元素,可以根据元素某个特征进行排序,如需按照倒序排序,可以在第二个参数列表中传入:Ordering[any].reverseList.sortWith():参数也为函数类型:需要传入两个元素,参数的函数体需返回一个boolean类型。
  6. 折叠: 集合.foldLeft()()函数,下面解释。
  7. 简化规约:集合.reduce()函数,相比 fold()()方法少了一个初始值参数列表。

​ 对于6. 7. 中介绍的 fold()(),reduce() 方法,可以通过下面这个合并两个map的案例,进行深入理解:

foldleft()()函数源码解析 :
 override /*TraversableLike*/
  def foldLeft[B](z: B)(@deprecatedName('f) op: (B, A) => B): B = {
    var acc = z						//累计变量acc 初始值即为第一个参数
    var these = this
    while (!these.isEmpty) {		//序列的长度不为零
      acc = op(acc, these.head)		//每次取一个头元素放入传进来的函数进行处理,并将结果赋给累计变量
      these = these.tail         	//除了头就是尾
    }
    acc								//最终将累计变量返回
  }
通过源码可以看出集合的折叠方法为多阶函数(函数柯里化)
第一个参数列表为: 初始值
第二个参数列表为: 可以理解为简化的规则:将集合的元素做何种处理,一般都是传一个lambda表达式
函数测试:
  //fold(),foldLeft(),foldRight()方法测试
  @Test
  def test_foldMethod(): Unit = {
    val list1 = List(9, 2, 5, 7)
    println(list1.foldLeft(10)((acc, elem) => acc + elem)) //会处理后的结果保存在acc中
    //可以简写为
    println(list1.fold(10)(_ + _)) //进行累加         执行过程为:10 + 9 + 2 + 5 + 7

    println(list1.fold(10)(_ - _)) //执行过程为     10 - 9 - 2 - 5 - 7

    //fold()底层调用了foldLeft()这里就不进行测试了
    //foldRight() 方法的执行过程与foldLeft()方法并不相同,可以理解为初始值从右边与元素进行简化处理
    println(list1.foldRight(10)(_ - _)) //  9 - (2 - (5 - (7 - 10)))
  }

 @Test
  def Test_reduceMethod(): Unit = {
    //简化规约:集合.reduce()方法,相比fold()()方法少了一个初始值参数列表
    val list1 = List(9, 2, 5, 7)
    println(list1.reduceLeft(_ - _)) //9 - 2 - 5 - 7
    println(list1.reduceRight(_ - _)) //(9 - (2 - (5 - 7)))

  }
合并两个map集合
@Test
def Test_MergeMap(): Unit = {
  //在工作中,我们往往有合并两个map集合的需求,即:合并相同key的value,而不是进行覆盖操作
  //在scala语言中,我们可以使用集合.fold()()方法对集合进行处理
  val map1 = mutable.Map("hello" -> 3, "word" -> 5)
  val map2 = mutable.Map("hello" -> 4, "scala" -> 4)

  //使用折叠方法: 集合.foldLeft()()方法
  //将map1作为初始值,map1会先赋给accMap累计变量,为初始值
  val stringToInt = map2.foldLeft(map1)((accMap, kv) => {
    //先取出map2中的key/value,通过二元组取元素的方式
    val key = kv._1
    val value = kv._2
    // 使用getOrElse()方法判断集合中是否有相同key 的键值对,该方法返回值:有key就返回value,没有就返回0
    //更新accMap并返回
    accMap(key) = accMap.getOrElse(key, 0) + value
    accMap
  })
  println(stringToInt)
}

普通WordCount案例

1)需求

​ 单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果

2)主要使用map()、groupBy()、 sortBy()、 take()函数

代码实现:

@Test
  def simpleWordCount(): Unit = {
    // 1. 简单的wordCount
    val lineDatas = List(
      "hello java",
      "hello scala",
      "hello world",
      "hello spark",
      "hello flink",
      "hello spark flink form scala"
    )
    val strings = Array("hello world")
    strings.map(_.split(" "))
    val flatMapList=lineDatas.flatMap(_.split(" "))
    //这种情况比较简单,可以直接使用映射方法,直接操作集合中的元素即可
    val resultMap = flatMapList.groupBy(word => word).map(kv => (kv._1,kv._2.length))
    // 提取top N
    println(resultMap.toList)    //List((world,1), (java,1), (flink,2), (spark,2), (scala,2), (hello,6), (form,1))
    //根据value进行降序排序
    println(resultMap.toList.sortBy(kv => kv._2)(Ordering[Int].reverse).take(3))

  }
复杂WordCount案例

代码实现:

@Test
def Test_complexWordCount(): Unit ={
  // 二、复杂版本
  //数据由二元组形成的List。_2:表示这行句子出现的次数
  val lineCountTupleList: List[(String, Int)] = List(
    ("hello", 1),
    ("hello world", 2),
    ("hello scala", 3),
    ("hello spark from scala", 4)
  )
  // 第一种做法:直接将单词和次数转化为对应次数的单词
  val resultMap = lineCountTupleList
    .map(elem => (elem._1 + " ") * elem._2)
    .flatMap(_.split("\\s+"))
    .groupBy(word => word)
    .map(kv => (kv._1, kv._2.size))
    .toList.sortWith(_._2 > _._2)
    .take(3)
  println(resultMap)

  //推荐做法:
  // 第二种做法:将元集合中的二元组转化为(单词,次数)的形式,在进行统计
  // 使用map()函数拿到集合中的元素
  val newList: List[Array[(String, Int)]] = lineCountTupleList.map(
    kv => {
      val wordsArr = kv._1.split("\\s+")
      //对数组中元素重新组合 => Array[(String,Int)] 数据类型为二元组的数组
      wordsArr.map(word => (word, kv._2)) //返回
    }
  )
  //newList.foreach(_.foreach(print))
  //扁平化List集合中的数组集合
  val flattenList:List[(String, Int)] = newList.flatten
  //分组:将相同单词的二元组分成
  //println(flattenList.groupBy(_._1))
  //统计
  val resultList: List[(String, Int)] = flattenList.groupBy(_._1).map(kv => {
    val value = kv._2
    (kv._1, value.map(_._2).sum)
  }).toList.sortBy(_._2)(Ordering[Int].reverse).take(3)
  println(resultList)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值