sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
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 + List.sum(t)
case _ => 101
}
问x的值,是个模式匹配的题目,结果是3,我们可以很清晰的看到第一个case由于第三个数不是3而是4所以走下一个,由于不是Nil,所以再下一个,结果能匹配上,x绑定1,y绑定2,结果是3
实现一个List的tail方法
实现思路,如果是一个Nil,则抛出异常,否则将list按照Cons进行分割,则t就是tail
def tail[A](list: List[A]): List[A] =
list match {
case Nil => throw new Exception("error")
case Cons(_, t) => t
}
实现setHead方法,替换头部元素
实现思路,判断list是不是Nil,如果是Nil,则抛出异常,否则将头部绑定为x即可
def setHead[A](x: A, list: List[A]): List[A] = {
list match {
case Nil => throw new Exception("error")
case Cons(_, xs) => Cons(x, xs)
}
实现一个drop,移除指定元素
实现思路:
如果移除元素个数小于等于0,则返回list本身,否则,如果list是空,则返回空,如果是Cons,则递归移除,调用本身,尾部作为list,移除个数由于第一个元素已经被移除了,所以为n-1
@tailrec
def drop[A](list: List[A], n: Int): List[A] = {
if (n <= 0) list
else list match {
case Nil => Nil
case Cons(_, xs) => drop(xs, n - 1)
}
}
实现dropWhile,移除符合条件的元素,直到第一个不符合条件的
实现思路
判断list如果是Cons,则判断第一个元素是否能被移除,如果能则tail递归调用移除方法,否则直接返回list
@tailrec
def dropWhile[A](l: List[A], f: A => Boolean): List[A] = {
l match {
//case Cons(x, xs) => if (f(x)) dropWhile(xs, f) else l
case Cons(x, xs) if f(x) => dropWhile(xs, f)
case _ => l
}
}
实现init,返回除最后一个元素外的其他元素
实现思路,如果是list是Nil,则抛出一个异常,如果是Cons(x,Nil)则返回Nil,如果Cons(x,xs)则新的Cons的head为x,尾部则为init(xs)
def init[A](l: List[A]): List[A] = l match {
case Nil => throw new Exception("empty")
case Cons(x, Nil) => Nil
case Cons(x, xs) => Cons(x, init(xs))
}
实现一个foldRight
其实就是一个初始值,一个操作函数,然后对List的每个元素依次调用函数
实现思路:如果List是Nil,则初始值z作为最终结果,否则,则调用f函数,让我们看一下f的类型签名,接收两个参数,分别为A和B类型,最终结果是B类型,那么这里我们A类型的自然是x,而B类型我们可以知道递归调用xs的返回值类型是B,所以最终写法是f(x,foldRight(xs,z)(f))
def foldRight[A, B](as: List[A], z: B)(f: (A, B) => B): B = as match {
case Nil => z
case Cons(x, xs) => f(x, foldRight(xs, z)(f))
}
实现length方法
这个在这里就是用到foldRight
思路,初始值为1,传到foldRight的f函数为(xs,acc) => acc + 1 ,也就是在递归的时候有一个元素则在原来的结果上+1,这里我们要看一下foldRight的类型签名是A类型的as和Int类型的acc,为啥acc是Int呢,他的类型是在(as,1)的时候被确定的,和1是同一个类型
def length[A](as: List[A]): Int = foldRight(as, 1)((xs, acc) => acc + 1)
实现foldLeft
实现思路和foldRight类似,就是函数f有了变化,这里是将B和A转化为B,也就是一个从左向右,一个从右向左的区别,所以对于Cons(x,xs),则可以进行尾递归,f可以将z作为B类型的传入,并传入Cons的第一个元素,得到一个B类型的,再和尾部进行foldLeft
@tailrec
def foldLeft[A, B](as: List[A], z: B)(f: (B, A) => B): B = as match {
case Nil => z
case Cons(x, xs) => foldLeft(xs, f(z, x))(f)
}