scala-10函数式编程之常用函数

scala函数值编程之常用函数

  • 面向函数式编程
  • 遍历 - foreach
  • 映射 - map
  • 扁平化映射 - flatmap
  • 过滤 - filter
  • 排序 - sort
    • 默认排序-sorted
    • 按照指定关键字排序 sortBy
    • sortWith
  • 分组 - groupBy
  • 聚合 - reduce
  • 折叠 - fold
    • Reduce和Fold区别

面向函数式编程

  • 面向函数式编程是一种编程范式。
  • 可以简单的把面向函数式编程理解为:把函数作为参数传递到方法中,该函数会作用在集合中元素上,最后函数体来控制最终的业务逻辑

遍历 - foreach

方法描述

foreach(f:(A)=>Unit):Unit

方法说明

foreach API 说明
参数 f: (A) ⇒ Unit 接收一个函数对象
函数的输入参数为集合的元素
返回值为空
返回值 Unit

详细释义

  • foreach()的参数类型f是个匿名函数:(A)=>Unit,foreach的返回类型是Unit,即第二个Unit
  • 匿名函数(A)=>Unit的参数列表是(A),在=>右侧的函数体中处理业务逻辑。最后放回一个空值,即第一个Unit是匿名函数的返回类型(空)
  • A是foreach中每个元素的类型,每个元素A都经过函数处理。
  • 调用foreach的集合决定A的类型。如:list.foreach,则A的数据类型和list中的元素数据类型一致

示例

scala> val list= List(1,2,3,4)
list: List[Int] = List(1, 2, 3, 4)

//定义一个匿名函数传入foreach中
scala> list.foreach((x:Int)=>println(x))
1
2
3
4

//scala支持类型推断,省略类型Int
scala> list.foreach((x)=>println(x))
1
2
3
4

//当函数参数,只在函数体重出现一次,而且函数体没有嵌套调用时,可以使用下划线来简化函数定义
scala> list.foreach(println(_))
1
2
3
4

//最简写
scala> list.foreach(println)
1
2
3
4

映射 - map

方法描述

def map[B](f:(A)=>B):TraversableOnce[B]

方法说明

map方法 API 说明
泛型 [B] 指定map方法最终返回的集合泛型
参数 f: (A) ⇒ B 传入一个函数对象
该函数接收一个类型A(要转换的列表元素)
返回值为类型B
返回值 TraversableOnce[B] B类型的集合

详细释义

  • B是map方法的参数类型,map中的每一个函数经过匿名函数f处理之后,返回B类型的的集合,即TraversableOnce[B]
  • 匿名参数f的参数类型为A,匿名参数f的返回类型为B

示例

scala> val list= List(1,2,3,4)
list: List[Int] = List(1, 2, 3, 4)

//定义一个匿名函数。匿名函数参数为Int类型,返回值为x*10的类型。(x*10为函数体最后一行,x*10的类型即为函数体返回的类型)
scala> list.map((x:Int)=>x*10)
res5: List[Int] = List(10, 20, 30, 40)

//scala支持类型腿短,省略参数类型
scala> list.map(x=>x*10)
res6: List[Int] = List(10, 20, 30, 40)

//参数x只在函数体中出现一次,且函数体没有嵌套调用,用_来简化定义
scala> list.map(_*10)
res7: List[Int] = List(10, 20, 30, 40)

扁平化映射 - flatmap

方法描述

def flatMap[B](f:(A)=>GenTraversableOnce[B]):TraversableOnce[B]

方法说明

flatmap方法 API 说明
泛型 [B] 最终要转换的集合元素类型
参数 f: (A) ⇒ GenTraversableOnce[B] 传入一个函数对象
函数的参数是集合的元素
函数的返回值是一个集合
返回值 TraversableOnce[B] B类型的集合

详细释义

  • 匿名函数f通过函数体处理调用flatmap中的每一个元素,最处理一个元素生成一个子集合,最终将所有子集合中的元素抽取出来组成一个大的新的集合
  • flatmap实际是将原集合先调用map,然后调用flatten

示例

scala> val list=List("hello world","hadoop spark hive")
list: List[String] = List(hello world, hadoop spark hive)

//使用flatMap进行扁平化处理,得到其中的所有子集合的所有元素
scala> list.flatMap(x=>x.split(" "))
res9: List[String] = List(hello, world, hadoop, spark, hive)

//函数体重使用一个x并且没有嵌套函数,用_简化
scala> list.flatMap(_.split(" "))
res10: List[String] = List(hello, world, hadoop, spark, hive)

//flatMap的本质是先调用map后调用flatten
scala> list.map(_.split(" ")).flatten
res11: List[String] = List(hello, world, hadoop, spark, hive)

//调用map生成新的List,List中的每个元素是个数组
scala> val m = list.map(_.split(" "))
m: List[Array[String]] = List(Array(hello, world), Array(hadoop, spark, hive))

//对新的List进行扁平化处理,抽取每个子集合的元素生成一个新的String集合
scala> m.flatten
res12: List[String] = List(hello, world, hadoop, spark, hive)

过滤 - filter

过滤符合一定条件的元素

方法描述

def filter(p:(A)=>Boolean):TraversableOnce[A]

方法说明

filter方法 API 说明
参数 p: (A) ⇒ Boolean 传入一个函数对象
接收一个集合类型的参数
返回布尔类型,满足条件返回true, 不满足返回false
返回值 TraversableOnce[A] 列表

详细释义

  • 只有经过P处理后的结果为true的元素才会被保留下来
  • 最终所有被保留下来的元素进入TraversableOnce[A],TraversableOnce[A]集合作为filter的返回值

示例

scala> val list=List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)

//过滤出小于3的元素
scala> list.filter(_<3)
res13: List[Int] = List(1, 2)

//过滤出小于3的元素后,每个元素*10生成新的集合
scala> list.filter(_<3).map(_*10)
res14: List[Int] = List(10, 20)

排序 - sort

scala集合中支持以下几种排序

  • sorted 默认排序,升序
  • sortedBy 按照的指定关键字排序,默认升序
  • sortWith 自定义排序

默认排序-sorted

示例

scala> val list=List(5,1,2,4,3)
list: List[Int] = List(5, 1, 2, 4, 3)

//默认就是升序
scala> list.sorted
res30: List[Int] = List(1, 2, 3, 4, 5)

按照指定关键字排序 sortBy

根据传入的函数转换后,再进行排序。默认升序
方法描述

def sortedBy[B](f:(A)=>B):List[A]

方法说明

sortBy方法 API 说明
泛型 [B] 按照什么类型来进行排序
参数 f: (A) ⇒ B 传入函数对象
接收一个集合类型的元素参数
返回B类型的元素进行排序
返回值 List[A] 返回排序后的列表

示例

scala> val list = List("1 cTest","2 aTest","3 bTest","4 aaTest")
list: List[String] = List(1 cTest, 2 aTest, 3 bTest, 4 aaTest)

//按照字符串进行排序,默认升序
scala> list.sortBy(x=>x.split(" ")(1))
res16: List[String] = List(2 aTest, 4 aaTest, 3 bTest, 1 cTest)

sortWith

自定义排序,根据一个函数来进行自定义排序

方法描述

def sortWith(lt:(A,A)=>Boolen):List[A]

方法说明

sortWith方法 API 说明
参数 lt: (A, A) ⇒ Boolean 传入一个比较大小的函数对象
接收两个集合类型的元素参数
返回两个元素大小,小于返回true,大于返回false
返回值 List[A] 返回排序后的列表

详细释义

  • lt的返回结果是true,则保持元素原位置不变
  • lt的返回结果是false,则调换原来的元素位置

示例

scala> val list = List(2,3,1,6,4,5)
list: List[Int] = List(2, 3, 1, 6, 4, 5)

//降薪排列
scala> list.sortWith((x,y)=>(x>y))
res17: List[Int] = List(6, 5, 4, 3, 2, 1)

//升序排列
scala> list.sortWith((x,y)=>(x<y))
res18: List[Int] = List(1, 2, 3, 4, 5, 6)

//x和y都只在函数体中出现了一次,且没有嵌套函数,用_简写
scala> list.sortWith(_<_)
res19: List[Int] = List(1, 2, 3, 4, 5, 6)

分组 - groupBy

  • groupBy表示按照函数将列表分成不同的组
  • 一般在需要将数据按照分组来进行统计分析时,会用到分组方法group by

方法描述

def groupBy[K](f:(a)=>k):Map[K,List[A]]

方法说明

groupBy方法 API 说明
泛型 [K] 分组字段的类型
参数 f: (A) ⇒ K 传入一个函数对象
接收集合元素类型的参数
返回一个K类型的key,这个key会用来进行分组,相同的key放在一组中
返回值 Map[K, List[A]] 返回一个映射,K为分组字段,List为这个分组字段对应的一组数据

详细释义

  • 每次传递进来的K值相同则分到同一组,分组依据是匿名函数f
  • 返回值是个Map,K是原集合笔筒的K值的集合,list为每个K对应的自己的一组数据

示例

scala> val a = List("张三"->"", "李四"->"", "王五"->"男")
a: List[(String, String)] = List((张三,), (李四,), (王五,))

//按照性别分组
scala> a.groupBy((kv:(String,String))=>{kv._2})
res2: scala.collection.immutable.Map[String,List[(String, String)]] = Map(-> List((张三,), (王五,)),-> List((李四,)))

//scala支持自动推断,省略类型
scala> a.groupBy(kv=>{kv._2})
res3: scala.collection.immutable.Map[String,List[(String, String)]] = Map(-> List((张三,), (王五,)),-> List((李四,)))

//kv在函数体中仅出现一次,且没有嵌套函数,使用_简写
scala> a.groupBy(_._2)
res4: scala.collection.immutable.Map[String,List[(String, String)]] = Map(-> List((张三,), (王五,)),-> List((李四,)))

//将分组后的映射转换为性别->人数 的元组列表
scala> res4.map(x=>x._1->x._2.size)
res5: scala.collection.immutable.Map[String,Int] = Map(-> 2,-> 1)

示例2

scala> val a =List("zhangSan"->10,"lisi"->10,"wangwu"->20)
a: List[(String, Int)] = List((zhangSan,10), (lisi,10), (wangwu,20))

//按照list的元素的第二个元素分组
scala> a.groupBy((kv:(String,Int))=>{kv._2})
res6: scala.collection.immutable.Map[Int,List[(String, Int)]] = Map(20 -> List((wangwu,20)), 10 -> List((zhangSan,10), (lisi,10)))

//按照List的元素的第一个元素分组
scala> a.groupBy((kv:(String,Int))=>{kv._1})
res7: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(zhangSan -> List((zhangSan,10)), lisi -> List((lisi,10)), wangwu -> List((wangwu,20)))

聚合 - reduce

  • reduce表示将列表传入一个函数进行聚合计算
  • reduce默认调用reduceLeft
  • reduce底层实际调用的是递归函数

scala2.11.2源码

def reduce[A1 >: A](op: (A1, A1) => A1): A1 = reduceLeft(op)

 /** Applies a binary operator to all elements of this $coll,
   *  going left to right.
   *  $willNotTerminateInf
   *  $orderDependentFold
   *
   *  @param  op    the binary operator.
   *  @tparam  B    the result type of the binary operator.
   *  @return  the result of inserting `op` between consecutive elements of this $coll,
   *           going left to right:
   *           {{{
   *             op( op( ... op(x_1, x_2) ..., x_{n-1}), x_n)
   *           }}}
   *           where `x,,1,,, ..., x,,n,,` are the elements of this $coll.
   *  @throws UnsupportedOperationException if this $coll is empty.   */
  def reduceLeft[B >: A](op: (B, A) => B): B = {
    if (isEmpty)
      throw new UnsupportedOperationException("empty.reduceLeft")

    var first = true
    var acc: B = 0.asInstanceOf[B]

    for (x <- self) {
      if (first) {
        acc = x
        first = false
      }
      else acc = op(acc, x)
    }
    acc
  }

方法描述

def reduce[A1 >:A](op:(A1,A1) => A1):A1

方法说明

reduce方法 API 说明
泛型 [A1 >: A] (下界)A1必须是集合元素类型的子类
参数 op: (A1, A1) ⇒ A1 传入函数对象,用来不断进行聚合操作
第一个A1类型参数为:当前聚合后的变量
第二个A1类型参数为:当前要进行聚合的元素
返回值 A1 列表最终聚合为一个元素

详细释义

  • 第一次遍历:集合中第一个元素赋值给第一个A1,第二个元素赋值给第二个A1
  • 第二次遍历:将两个A1元素匿名函数op处理后的结果赋给第一个A1,将集合中的第三个元素赋值给第二个A2
  • 重复执行上面两步,直到处理完整个集合的元素。
  • 第一个下划线表示第一个参数,就是历史的聚合数据结果
  • 第二个下划线表示第二个参数,就是当前准备要聚合的数据元素

示例

scala> val a = List(1,2,3,4,5,6,7,8,9,10)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

//集合中第一个元素赋给x,第二个赋给y
//相加后的元素赋给x,第三个元素赋给y
//以此类推
scala> a.reduce((x:Int,y:Int)=>x+y)
res8: Int = 55

// 第一个下划线表示第一个参数,就是历史的聚合数据结果
// 第二个下划线表示第二个参数,就是当前要聚合的数据元素
scala> a.reduce((x,y)=>x+y)
res9: Int = 55

//x,y都在函数体中出现一次,且没有嵌套函数。使用_简化写法。另外,由于有不止一个变量,所以将_,_._+_写成_._
scala> a.reduce(_+_)
res12: Int = 55

//从左侧开始聚合
scala> a.reduceLeft(_+_)
res13: Int = 55

//从右侧开始聚合
scala> a.reduceRight(_+_)
res14: Int = 55

折叠 - fold

  • fold类似reduce,不过前面指定了一个初始值参数
  • fold默认调用foldLeft
  • 实际上这是一种柯里化写法

scala2.11.2源码

def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)

 def foldLeft[B](z: B)(op: (B, A) => B): B = {
    var result = z
    this foreach (x => result = op(result, x))
    result
  }

方法值描述

def fold[A1>: A](z:A1)(op:(A1,A1)=>A1):A1

方法说明

More Actionsreduce方法API说明泛型[A1 >: A](下界)A1必须是集合元素类型的子类参数1z: A1初始值参数2op: (A1, A1) ⇒ A1传入函数对象,用来不断进行折叠操作
第一个A1类型参数为:当前折叠后的变量
第二个A1类型参数为:当前要进行折叠的元素返回值A1列表最终折叠为一个元素

示例

scala> val a = List(1,2,3,4,5,6,7,8,9,10)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

//给定初始值0,对list进行累加操作
scala> a.fold(0)(_+_)
res19: Int = 55

//给定初始值10,对List进行累加操作
scala> a.fold(10)(_+_)
res20: Int = 65

//给定初始值10,从左侧对开始对list进行折叠
scala> a.foldLeft(10)(_+_)
res21: Int = 65

//给定初始值10,从右侧开始对list进行折叠
scala> a.foldRight(10)(_+_)
res22: Int = 65

Reduce和Fold区别

  • 初始值
    • Reduce初始值是集合元素的头或尾(left或者right)
    • Fold必须手动指定初始值
  • 空集合操作
    • Reduce进行空集合操作会抛异常
    • Fold进行空集合操作结果为初始值
  • 返回值
    • Reduce最终聚合的元素必须和调用Reduce方法的集合中元素一致
    • Fold最终折叠得到的元素类型可以和调用Fold中的元素不一致
  • 底层实现
    • Reduce底层采用递归实现
    • Fold底层采用foreach实现

你可能感兴趣的:(Scala)