Scala函数式程序设计原理 week5 List

List

list是函数式编程中得基础数据结构。
lists和arrays的区别在于

  • list是不可修改的,其元素值不可变
  • list是递归的,而array是展平的

与array一样,list是同质的(homogeneous),其元素必须为相同类型。
一个含有元素类型T的列表写为scala.List[T]或简写为List[T]

List构造器

所有的列表构造于

  • 空列表Nil
  • construction操作符::(读作cons):x::xs产生一个新的列表,首元素是x,后面是xs的所有元素

右结合性

::是右结合的,通过::列表将从末端开始构建。

A::B::C //解释为A::(B::C)

List上的操作

所有列表上的操作都可以表达成以下几种操作
head,tail,isEmpty

List模式

也可以用模式匹配解析列表

  • Nil Nil常量
  • p::ps 一个匹配列表头部和尾部的模式
  • List(p1,…,pn) 和p1::…::pn::Nil 相同

List方法

方法 子列表和访问元素
xs.length xs的元素个数
xs.last 获取最后一个元素,若不空
xs.init 获取除了最后一个元素的列表
xs take n 获取前n的元素的列表
xs drop n 移除前n个元素的列表
xs(n) 指定所以的元素
方法 创建新列表
xs ++ ys 创建包含xs和ys所有元素的列表
xs.reverse 创建逆序列表
xs updated (n,x) 更新索引n出的元素为x
方法 查找元素
xs indexOf x 返回指定元素索引
xs contains x 是否包含指定元素

对偶和元组

对偶

包含元素x,y的对偶写作(x,y)

val pair = ("answer",42) > pair:(String,Int)=(answer,42)

以上对偶的类型为(String,Int)
对偶可以用作模式:

val (label,value) = pair

元组

元组(T1,...,Tn)的是参数化类型scala.Tuplen[T1,...Tn]的缩写。

隐式参数

函数或方法可以带有一个标记为implicit的参数列表。这种情况下,编译器会查找缺省值,提供给该函数或方法。

case class Delimiters(left:String,right:String)
def quote(what:String)(implicit delims:Delimiters)=delims.left+what+delims.right

可以用一个显式的Delimiters对象来调用quote方法,就像这样:

quote("hello")(Delimiters("<<",">>"))//将返回<<heelo>>

注意这里有两个参数列表。这个函数是“柯里化”的。
也可以略去隐式参数列表:

quote("Hello")

这种情况下,编译器会查找一个类型为Delimiters的隐式值。这必须是一个声明为implicit的值。编译器将会在如下两个地方查找这样的一个对象

  • 在当前作用域所有可以用单个标识符指代的满足类型要求的val和def
  • 在所要求类型相关联的类型的伴生对象。相关联的类型包括所要求类型本身,以及它的类型参数。

List高阶函数(函数映射到集合)

Map

当想要对集合中所有元素进行变化时,map方法可以将某个函数应用到集合中的每个元素并产出其结果的集合。

val names = List('a','b','c')
names.map(_.tpUpperCase)//List('A','B','C')

Flatmap

如果函数产出一个集合而不是单个值得话,若想将所有得值串接在一起,使用flatMap
如果使用flatMap并传入返回Option得函数,最终返回得集合将包含所有的v值,前提是函数返回Some(v)。

foreach

如果应用到函数各个元素仅仅是为了它的副作用而不关心函数值,使用foreach

Filter

另一个常用操作是筛选所有满足条件的元素。

  val pair = List(1,2,3,4,5,6)
  pair.filter(x => x<3)//1,2

Filter的变形

化简,折叠,扫描

化简

map方法将一元函数应用到集合的所有元素。下面介绍用二元函数组合集合中的元素。类似c.reduceLeft(op)这样的调用将op相继应用到元素。

List(1,7,2,9).reduceLeft(_-_)//((1-7)-2)-9=-17
List(1,7,2,9).reduceRight(_-_)//1-(7-(2-9))

折叠

以不同于集合首元素的初始元素开始计算,对coll.foldLeft(init)(op)的调用将会计算

List(1,7,2,9).foldLeft(0)(_-_)
将得到0-1-7-2-9 = -19

初始值和操作符是两个分开定义的”柯里化”参数,这样Scala就能用初始值的类型来推断出操作符的类型定义。
也可以用/:操作符写foldLeft操作,

(0/:List(1,7,2,9))(_-_)

/:操作符而言,初始值是第一个操作元。
折叠有时候可以作为循环的替代。

val freq = scala.collection.mutable.Map[Char,Int]()
for (c<-"Hello") freq(c) = freq.getOrElse(c,0) + 1

(Map[Char,Int]() /: "Hello"){
(m,c) => m + (c->(m.getOrElse(c,0)+1))
}

扫描

scanLeftscanRight方法将折叠和映射操作结合在一起。得到包含所有中间结果的集合

(1 to 10).scanLeft(0)(_+_)//产出所有中间结果和最后的和
Vector(0,1,3,6,10,...,45,55)
全部评论

相关推荐

牛客717484937号:双飞硕没实习挺要命的
点赞 评论 收藏
分享
09-29 17:44
已编辑
蔚来_测(准入职员工)
//鲨鱼辣椒:见不了了我实习了四个月上周再投筛选了一天就给我挂了
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务