3.1 下面的匹配表达式结果是什么?
val x = List(1,2,3,4,5) match {
case Cons (x,Cons (2,Cons(4,_ )))=> x
case Nil => 42
case Cons(x, Cons (y, Cons(3, Cons(4, _)) ) ) =>x+y
case Cons(h, t) => h + sum(t)
case _ => 101
package com.lyzz.test.scala
object test_03 {
def main(args: Array[String]): Unit = {
val x = List(1,2,3,4,5) match {
case x::(2 ::(4::_)) => x
case Nil => 42
case x::(y::(3::(4::_))) => x + y
case h::t => h + sum(t)
case _ => 101
}
println(x)
}
def sum(ints: List[Int]): Int = ints match {
case Nil => 0
case x :: xs => x + sum(xs)
}
}
结果是 3
3.2 实现tail函数,删除一个List的第一个元素。注意这个函数的时间开销是常量级的。 如果列表是Nil,在实现的时候会有什么不同的选择?我们在下一章再回顾这个问题。
package com.lyzz.test.scala
object test_03 {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4,5)
val list1 = List()
println(tail(list))
println(list1)
}
def tail[A] (l: List[A]): List[A] = l match {
case Nil => Nil
case _::t => t
}
}
输出结果
List(2, 3, 4, 5)
List()
3.3
使用相同的思路,实现函数setHead用一个不同的值替代列表中的第一个元素。
package com.lyzz.test.scala
object tese_03 {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4,5)
val list1 = List()
println(setHead(list,20))
println(setHead(list1,"Alex"))
}
def setHead[A] (y: List[A],x: A): List[A] = y match {
case Nil => x +:Nil
case _::t => x::t
}
结果:
List(20, 2, 3, 4, 5)
List(Alex)
3.4 把tail泛化为drop函数,用于从列表中刪除前n个元素。注意,这个函数的时间开销只需要与drop的元素个数成正比一不需 要复制整个列表。
package com.lyzz.test.scala
object test_03 {
def main(args: Array[String]): Unit = {
val ints: List[Int] = List(1,2,3,4,5,6,7,8,9)
println( drop(ints,4))
}
// 递归调用删除
def drop[A] (L: List[A],n: Int): List[A] ={
if(n == 0) L
else L match {
case Nil => Nil
case _::t => drop(t,n-1)
}
}
}
结果
List(5, 6, 7, 8, 9)
3.5
实现dropWhile函数,删除列表中前缀全部符合判定的元素。
def dropWhile[A] (l: List[A], f: A => Boolean) : List [A]
package com.lyzz.test.scala
object test_03 {
def main(args: Array[String]): Unit = {
val ints: List[Int] = List(1,3,5,7,8,9)
val f = (x: Int) =>{x%2==1}
println(dropWhile(ints,f))
println(dropWhile_curry(ints)(f))
}
def dropWhile[A](l: List[A], f: A => Boolean): List[A] = l match {
case h::t if(f(h)) =>dropWhile(t,f)
case _ => l
}
//改进:currying
def dropWhile_curry[A](l: List[A])(f: A => Boolean): List[A] = l match {
case h::t if(f(h)) => dropWhile_curry(t)(f)
case _ => l
}
}
3.6 不是所有的实现都这么令人满意,实现一个init函数,返回一个列表,它包含原列表中除了最后一个元素之外的所有元素。比如,传入List(1,2,3,4)给init函数会返回List(1,2,3),为什么这个函数不能实现同tail一样的常量级时间开销?
def init[A] (l: List[A]): List[A]
package com.lyzz.test.scala
object test_03 {
def main(args: Array[String]): Unit = {
val ints: List[Int] = List(1,3,5,7,8,9)
println(init(ints))
}
def init[A](l: List[A]): List[A] = l match {
case Nil => Nil
case _::Nil => Nil
case h::t => h::init(t)
}
}
结果:
List(1, 3, 5, 7, 8)
3.8
当你对foldRight传人Nil和Cons时,看看会发生什么?例如: foldRight (
List(1,2,3,4),Nil:List[Int]) (Cons(_ ,_ ) )。 "说到foldRight和List
数据结构之间的关系,你有什么想法?
package com.lyzz.test.scala
object test_03 {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4,5)
println(list.foldRight(Nil:List[Int])(_::_))
}
}
结果:
List(1, 2, 3, 4, 5)
...刚开始学scala,还不是很了解,等以后了解再回来解答这题
3.9 使用foldRight计算List 的长度。
def length[A] (as: List[A]) : Int
package com.lyzz.test.scala
object test03 {
def main(args: Array[String]): Unit = {
val ints: List[Int] = List(1,1,1,1,5,4)
println(length(ints))
}
def foldRight[A,B](as: List[A],z:B)(f:(A,B)=>B):B =
as match {
case Nil => z
case x::xs =>f(x,foldRight(xs,z)(f)) //遍历完从最后一位开始操作
}
def length[A](as: List[A]):Int =foldRight(as,0)((_,xs)=>xs+1)
}
结果
6
3.10 我们实现的foldRight不是尾递归,如果List很大可能会发生StackOverflowError(我们称之为非栈安全的)。说服自己接收这种情况,然后用尾递归方式写另一个通用的列递归函数foldLeft。签名如下:
def foldLeft[A,B] (as: List[A], z: B) (f: (B, A) => B): B
package com.lyzz.test.scala
object test03 {
def main(args: Array[String]): Unit = {
val ints: List[Int] = List(1,1,1,1,5,4)
println(foldLeft(ints,0)(_ + _))
}
@annotation.tailrec
def foldLeft[A,B](as:List[A],z:B)(f:(B,A)=>B):B =
as match {
case Nil => z
case x::xs =>foldLeft(xs,f(z,x))(f) //直接从头开始f操作
}
}
答案:13
3.11 写一下sum、product函数,和一个用foldLeft计算列表长度的函数。
package com.lyzz.test.scala
object test03 {
def main(args: Array[String]): Unit = {
val ints: List[Int] = List(1,1,1,1,5,4)
println(length(ints))
println(sum(ints))
println(product(ints))
}
@annotation.tailrec
def foldLeft[A,B](as:List[A],z:B)(f:(B,A)=>B):B =
as match {
case Nil => z
case x::xs =>foldLeft(xs,f(z,x))(f) //直接从头开始f操作
}
def length[A](as: List[A]): Int = foldLeft(as,0)((xs,_)=>xs+1)
def product(l: List[Int]): Int =
l match {
case Nil => 1
case x::t => x*product(t)
}
def sum(l: List[Int] ): Int =
l match{
case Nil => 0
case x::t => x+sum(t)
}
}
3.12
写一个对原列表元素颠倒顺序的函数(List(1,2,3) 返回List(3,2,1) ),看看是否可用一种折叠( fold )实现。
package com.lyzz.test.scala
object test03 {
def main(args: Array[String]): Unit = {
val ints: List[Int] = List(1,1,1,1,5,4)
println(reverse(ints))
}
@annotation.tailrec
def foldLeft[A,B](as:List[A],z:B)(f:(B,A)=>B):B =
as match {
case Nil => z
case x::xs =>foldLeft(xs,f(z,x))(f) //直接从头开始f操作
}
def reverse[T](list: List[T]): List[T] = foldLeft(list:List[T],Nil:List[T])((res,cur)=>cur::res)
}
✧-练习3,13
难:你是否能根据foldRight来写-一个foldLeft ?有没有其他变通方式?通过foldLeft来实现foldRight很有用,因为这会让我们以尾递归的方式实现。意味着不管列表有多大都不会产生栈溢出。