More Function On Lists
写了三个比较有意思的函数,如下
def removeAt[T](n : Int, xs: List[T]): List[T] = {
if (n == 0)
xs match {
case List() => throw new Error("index out of range!")
case _::ys => ys
}
else
xs match {
case List() => throw new Error("index out of range!")
case x::ys => x :: removeAt(n-1, ys)
}
}
def removeAt[T](n : Int, xs : List[T]): List[T] = (xs take n-1) ++ (xs drop n)
// flatMap 操作
def flatten[T](xs : List[T]) : List[T] = {
xs match {
case List() => List()
case x :: ys => x match {
case list: List[T] => flatten(list) ++ flatten(ys)
case _ => x :: flatten(ys)
}
}
}
// List[T].take(n) 取前n个
// List[T].drop(n) drop掉前n个取剩下的
def concat[T](xs : List[T], ys : List[T]): List[T] =
xs match {
case List() => ys
case x :: zs => x :: concat(zs, ys)
}
Pairs and Tuples
// 归并排序
def msort(xs: List[Int]): List[Int] = {
val n = xs.length / 2
if (n == 0)
xs
else {
def merge(xs: List[Int], ys : List[Int]): List[Int] = {
(xs, ys) match {
case (Nil, y) => y
case (x, Nil) => x
case (x::x1, y::y1) => if (x < y) x :: merge(x1, ys) else y :: merge(xs, y1)
}
}
val (fst, snd) = xs splitAt n
merge(msort(fst), msort(snd))
}
}
// _1 代表第一个元素,_2代表第二个元素,都是逆变参数
class Tuple2[+T1, +T2](_1: T1, _2:T2) {
override def toString(): String = "(" + _1 + "," + _2 + ")"
}
Implicit Parameters
making sort more general
如果我们希望上面的归并排序可以更加general的话,我们会考虑加上泛型参数,但是加上泛型参数之后 <
会报错。
// 一种方法
def msort[T](xs: List[T])(lt : (T, T) => Boolean): List[T] = {
val n = xs.length / 2
if (n == 0)
xs
else {
def merge(xs: List[T], ys : List[T]): List[T] = {
(xs, ys) match {
case (List(), List()) => List()
case (List(), y) => y
case (x, List()) => x
case (x::x1, y::y1) => if (lt(x, y)) x :: merge(x1, ys) else y :: merge(xs, y1)
}
}
val (fst, snd) = xs splitAt n
merge(msort(fst)(lt), msort(snd)(lt))
}
}
scala.math.Ordering[T]
提供了比较的方法
// 另一种方法
def msort[T](xs: List[T])(ord: Ordering[T]): List[T] = {
val n = xs.length / 2
if (n == 0)
xs
else {
def merge(xs: List[T], ys : List[T]): List[T] = {
(xs, ys) match {
case (List(), List()) => List()
case (List(), y) => y
case (x, List()) => x
case (x::x1, y::y1) => if (ord.lt(x, y)) x :: merge(x1, ys) else y :: merge(xs, y1)
}
}
val (fst, snd) = xs splitAt n
merge(msort(fst)(ord), msort(snd)(ord)
}
}
// 值得一提的是,Ordering类中有很多现成的 Ordering 子类使用
trait IntOrdering extends Ordering[Int] {
def compare(x: Int, y: Int) = java.lang.Integer.compare(x, y)
}
implicit object Int extends IntOrdering with CachedReverse[Int]
msort(nums)(Ordering.Int)
定义隐式参数即加入关键字 implicit
def msort[T](xs: List[T])(implicit ord: Ordering[T]): List[T] = {
val n = xs.length / 2
if (n == 0)
xs
else {
def merge(xs: List[T], ys : List[T]): List[T] = {
(xs, ys) match {
case (List(), List()) => List()
case (List(), y) => y
case (x, List()) => x
case (x::x1, y::y1) => if (ord.lt(x, y)) x :: merge(x1, ys) else y :: merge(xs, y1)
}
}
val (fst, snd) = xs splitAt n
merge(msort(fst), msort(snd))
}
}
如果一个函数有一个隐式参数类型为T,编译器会寻找一个隐式定义
- is marked implicit.
- has a type compatible with T.
- is visible at the point of the function call, or is defined in a companion object associated with T.
否则,it's an error.
High-order List Functions
高阶函数
函数式编程语言允许程序员写一些generic
函数去实现一些通用模式,这就是高阶函数。
// 一些有意思的函数
def pack[T](xs : List[T]): List[List[T]] = xs match {
case List() => List()
case x :: _ => {
val (first, rest) = xs span (y => y == x)
first :: pack(rest)
}
}
def encode[T](xs : List[T]) : List[(T, Int)] = pack(xs).map(x => (x.head, x.length))
记录一些比较好用的函数
-
xs filterNot p
==xs filter (x => !p(x))
-
xs partition p
==(xs filter p, xs filterNot p)
-
xs takeWhile p
最长前缀满足条件的列表 xs dropWhile p
-
xs span p
==(xs takeWhile p, xs dropWhile p)
Reduction of Lists
上面所讨论的都是一种类似map
映射的转换,但是还有另一种常用的操作是combines the elements of a list using a given operator
. reduce/fold combinators
def sum(xs : List[Int]) = (0::xs) reduceLeft (_+_)
def product(xs : List[Int]) = (1::xs) reduceLeft (_*_)
// a more general function : foldLeft
def sum(xs : List[Int]) = (xs foldLeft 0) (_+_)
def product(xs : List[Int]) = (xs foldLeft 1) (_*_)
// 代码实现 foldLeft 和 foldRight
def reduceLeft(xs: List[T])(op: (T, T) => T): T = xs match {
case Nil => throw new Error("Nil.reduceLeft")
case x :: xs => foldLeft(xs)(x)(op)
}
def foldLeft[U](xs: List[T])(z: U)(op: (U, T) => U): U = xs match {
case Nil => z
case x :: xs => foldLeft(xs)(op(z, x))(op)
}
def reduceRight(xs: List[T])(op: (T, T) => T): T = xs match {
case Nil => throw new Error("Nil.reduceLeft")
case x :: Nil => x
case x :: xs => foldRight(xs)(x)(op)
}
def foldRight[U](xs: List[T])(z: U)(op: (U, T) => U): U = xs match {
case Nil => z
case x :: xs => op(foldRight(xs)(z)(op), x)
}
def concat(xs: List[T], ys: List[T]): List[T] =
(xs foldRight ys) (_ :: _)
def mapFun[T, U](xs: List[T], f: T => U): List[U] =
(xs foldRight List[U]()) ((a, b) => f(a) :: b)
def lengthFun[T](xs: List[T]): Int =
(xs foldRight 0) ((_, u) => u + 1)
当满足结合律和交换律的时候,foldLeft和foldRight是得到相同结果的(尽管它们的效率是不一样的).
object Test { // 加入一些测试
def mapFun[T, U](xs: List[T], f: T => U): List[U] =
(xs foldRight List[U]()) ((a, b) => f(a) :: b)
def lengthFun[T](xs: List[T]): Int =
(xs foldRight 0) ((_, u) => u + 1)
def main(args: Array[String]): Unit = {
val a = Array(1, 2, 3)
val b = 1 +: a
println(b.toList) // List(1, 1, 2, 3)
val c = List(1, 2, 3, 4, 5)
println(mapFun(c, (x : Int) => x + 1)) // List(2, 3, 4, 5, 6)
println(lengthFun(c)) // 5
}
}