您的位置:首页 > 其它

Play scala 4 List的实现

2014-12-26 18:11 225 查看
函数式的集合不允许 update value in place, 只能用函数操作集合,每个操作都产生新的集合。这样会造成大量copy吗? 令人惊异的是,No !

自己实现List

package ch3.dslist

sealed trait List[+A]  //sealed的作用: 所有继承List的类型都必须定义在本文件

case object Nil extends List[Nothing]

case class Cons[+A](head: A, tail: List[A]) extends List[A]

object List {
// 求和函数
def sum(ints: List[Int]): Int =  ints match {
case Nil => 0
case Cons(x, xs) => x + sum(xs)   // 用构造器作模式匹配
}

// 求积函数,要求只要其中一个为0就立即返回0
def product(nums: List[Double]) : Double = nums match {
case Nil => 1.0
case Cons(0.0, xs) => 0
case Cons(x, xs) => x * product(xs)
}

// 创建List的方法
def apply[A](as: A*):List[A] = {
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
}
}


测试
package ch3.dslist

object testList {
println("Welcome to the Scala worksheet")       //> Welcome to the Scala worksheet
val example = Cons(1, Cons(2, Cons(3, Nil)))    //> example  : ch3.dslist.Cons[Int] = Cons(1,Cons(2,Cons(3,Nil)))
val example2 = List(1.0, 2.0, 3.0)              //> example2  : ch3.dslist.List[Double] = Cons(1.0,Cons(2.0,Cons(3.0,Nil)))
List.sum(example)                               //> res0: Int = 6
List.product(example2)                          //> res1: Double = 6.0
}
2. 添加一下常用操作

def tail[A](l: List[A]): List[A] = l match {
case Nil => throw new Error("Nil.tail")
case Cons(x, xs) => xs
}

def drop[A] (l: List[A], n: Int): List[A] = {
if (n == 1) tail(l)
else drop(tail(l), n-1)
}

def dropWhile[A](l: List[A])(f: A => Boolean): List[A] = l match {
case Nil => Nil
case Cons(x, xs) =>
if (f(x)) dropWhile(xs)(f)
else Cons(x, dropWhile(xs)(f))
}

def setHead[A](l: List[A], h: A): List[A] = Cons(h, l)

// O(N)
def append[A](a1: List[A], a2: List[A]): List[A] = a1 match {
case Nil => a2
case Cons(x, xs) => Cons(x, append(xs, a2))
}
这些操作并没有大量copy,而是复用了内存。因为整体是immutable的,所有部分也是immutable的。当call tail时,只需将tail的引用返回就好了。不用担心以后因原来的list有变化,而影响作为返回值的list。
这个世界本来就应该immutable和muttable共存。因为有些操作中immutable的集合上操作更高效,比如tail,append。有些操作中muttable的集合上操作更高效,比如update一个元素

3.实现init函数,返回除最后一个元素之外,其它元素按顺序组成的List
def init[A](l: List[A]): List[A] = l match {
case Nil => Nil
case Cons(x, xs) =>
xs match {
case Nil => List()
case Cons(y, ys) => Cons(x, init(xs))
}
}
4. 实现foldRight函数。并用之改进sum和product

def foldRight[A, B](l: List[A], z: B)(f: (A, B) => B): B = l match {
case Nil => z
case Cons(x, xs) => f(x, foldRight(xs, z)(f))
}

def sum2(l: List[Int]) = foldRight(l, 0)(_ + _)

def product2(l: List[Double]) = foldRight(l, 1.0)(_ * _)
5. 用foldRight实现length函数

def length[A](l: List[A]): Int = foldRight(l, 0)((a ,b) => b +1)
6. 我们的foldRight函数的实现不是尾递归的,当List很大时容易造成stackOverflow。现在用尾递归实现一个foldLeft函数,并重新实现sum 和 product。

def foldLeft[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
def ff = 0
def loop(a : B, m:List[A]): B = m match {
case Nil => a
case Cons(x, xs) => loop(f(x, a), xs)
}
loop(z, l)
}
def sum3(l: List[Int]) = foldLeft(l, 0)(_ + _)
def product3(l: List[Double]) = foldLeft(l, 1.0) (_ * _)
将非尾递归改为尾递归的一般方法: 用循环结构重新实现算法,把这个循环结构写成新的递归

7.Write a function that transforms a list of integers by adding 1 to each element. (Reminder: this should be a pure function that returns a new !) List
给每个元素都加1
def addOne(l: List[Int]): List[Int] = l match {
case Nil => Nil
case Cons(x, xs) => Cons(x +1, addOne(xs))
}
8. Write a function that turns each value in a List[Double] into a . String
将Double转化为String
def all2String(l:List[Double]): List[String] = l match {
case Nil => Nil
case Cons(x, xs) => Cons(x.toString, all2String(xs))
}
9. 实现map函数

def map[A, B](l: List[A])(f: A => B): List[B] = l match {
case Nil => Nil
case Cons(x, xs) => Cons(f(x), map(xs)(f))
}
10. Write a function that removes elements from a list filter unless they satisfy a given predicate. Use it to remote all odd numbers from a . List[Int]
实现filter函数,并用它筛去List[Int]中的所有奇数
def filter[A](l: List[A])(f: A => Boolean): List[A] = l match {
case Nil => Nil
case Cons(x, xs) =>
if (f(x))  Cons(x, filter(xs)(f))
else filter(xs)(f)
}
11. 实现flatMap

def flatMap[A, B](l: List[A])(f: A => List[B]): List[B] = l match {
case Nil => Nil
case Cons(x, xs) =>
f(x) match {
case Nil => flatMap(xs)(f)
case Cons(y, ys) => append(f(x), flatMap(xs)(f))
}
}
12. 用flatMap实现filter
def filter2[A](l: List[A])(f: A => Boolean): List[A] = flatMap(l)(  x => if (f(x)) List(x)  else Nil)
13. 实现向量加法
比如:add(List(1,2,3), List(2, 3, 4)) = List(3, 5, 7)
def head[A](l: List[A]): A = l match {
case Nil => throw new Error("Nil.head")
case Cons(x, xs) => x
}

def add(a1: List[Int], a2: List[Int]): List[Int] = a1 match {
case Nil => Nil
case Cons(x, xs) => Cons(x + head(a2), add(xs, tail(a2)))
}
14. 判断一个序列是不是另一序列的子序列:def hasSubsequence[A](l: List[A], sub: List[A]): Boolean
我们用最自然的算法判断:拿第二个list与第一个list从头开始比较,如果不相等,就从第二个元素开始比较。
这个算法显然要依赖另外两个函数:1. equals函数,用于比较两个list 2. take函数,用于获取前n个元素
def take[A](l: List[A], n: Int): List[A] =  l match {
case Nil =>
if (n == 0) Nil
else throw new Exception("No element")
case Cons(x, xs) =>
if (n >= 1) Cons(x, take(xs, n-1))
else Nil
}

def equals[A](a: List[A], b: List[A]): Boolean = a match {
case Nil =>
b match {
case Nil => true
case _ => false
}
case Cons(x, xs) =>
b match {
case Nil => false
case Cons(y, ys) =>
if (x == y) equals(xs, ys)
else false
}
}

def hasSubsequence[A](a: List[A], b: List[A]): Boolean = {
if (length(a) < length(b)) false
else {
val c = take(a, length(b))
if (equals(c, b)) true
else hasSubsequence(tail(a), b)
}
}
显然,上述代码有很多地方可以优化,比如length函数和take函数调了很多次,会很浪费时间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐