本文叙述Collections里最常见的三种操作map, flatMap, filter,与For表达式的关系。
List对三种方法的实现
map在List的实现:
abstract class List[+T] {
def map[U](f: T => U): List[U] = this match {
case x :: xs => f(x) :: xs.map(f)
case Nil => Nil
}
}
flatMap在List的实现:
abstract class List[+T] {
def flatMap[U](f: T => List[U]): List[U] = this match {
case x :: xs => f(x) ++ xs.flatMap(f)
case Nil => Nil
}
}
filter在List的实现:
abstract class List[+T] {
def filter(p: T => Boolean): List[T] = this match {
case x :: xs =>
if (p(x)) x :: xs.filter(p) else xs.filter(p)
case Nil => Nil
}
}
For表达式
下面这段逻辑,可以在for里简单表达:
(1 until n) flatMap (i =>
(1 until i) filter (j => isPrime(i + j)) map
(j => (i, j)))
for {
i <- 1 until n
j <- 1 until i
if isPrime(i + j)
} yield (i, j)
for与map
for (x <- e1) yield e2
// translated to
e1.map(x => e2)
for与filter
for (x <- e1 if f; s) yield e2
// translated to
for (x <- e1.withFilter(x => f); s) yield e2
for与flatMap
for (x <- e1; y <- e2; s) yield e3
// translated to
e1.flatMap(x => for (y <- e2; s) yield e3)
for与Pattern Matching
结合前一篇文章(JSON表达)的例子,用for来做map、filter的操作:
val data: List[JSON] = ...
for {
JObj(bindings) <- data
JSeq(phones) = bindings("phoneNumbers")
JObj(phone) <- phones
JStr(digits) = phone("number")
if digits startsWith "212"
} yield (bindings("firstName"), bindings("lastName"))
for里面Pattern Matching的大致翻译过程:
pat <- expr
// to
x <- expr withFilter {
case pat => true
case _ => false
} map {
case pat => x
}
Exercise
for {
x <- 2 to N
y <- 2 to x
if (x % y == 0)
} yield (x, y)
可以翻译为:
(2 to N) flatMap (x =>
(2 to x) withFilter (y =>
x % y == 0) map (y => (x, y)))
参考自 Principles of Reactive Programming
全文完 :)