假设我有一些函数Int => Option[Int]
:
val f1: Int => Option[Int] = x => if (x < 10) Some(x + 1) else None
val f2: Int => Option[Int] = x => if (x < 10) Some(x + 2) else None
val f3: Int => Option[Int] = x => if (x < 10) Some(x + 3) else None
现在我想把它们组成和创建一个新函数,它累积中间结果,即f1
,f2
和{{1}的结果}。
所以我添加了一个新课程f3
:
Accumulator
现在我可以看到计算的所有中间结果:
class Accumulator(x: Int) {
val ox1 = f1(x)
val ox2 = ox1.flatMap(f2)
val ox3 = ox2.flatMap(f3)
def apply() = ox3
}
val f = {x => new Accumulator(x)}
我不喜欢这种方法,因为每次计算需要一个新类。您能否建议另一种方法来编写由scala> f(0)
res18: X = $$$a5cddfc4633c5dd8aa603ddc4f9aad5$$$$w$X@10596df6
scala> res18.ox1
res19: Option[Int] = Some(1)
scala> res18.ox2
res20: Option[Int] = Some(3)
scala> res18()
res21: Option[Int] = Some(6)
,f
和f1
组成的函数f2
,该函数也返回中间结果,即f3
的结果,f1
和f2
来电。
答案 0 :(得分:5)
为什么不将foldLeft
与函数列表一起使用?
def accumulate(x: Int, funcs: List[Int => Option[Int]]): List[Option[Int]] = funcs.foldLeft(List[Option[Int]]()) {
case (Nil, func) => List(func(x))
case (res :: tail, func) => res.flatMap(func) :: res :: tail
}.reverse
val f1: Int => Option[Int] = x => if (x < 10) Some(x + 1) else None
val f2: Int => Option[Int] = x => if (x < 10) Some(x + 2) else None
val f3: Int => Option[Int] = x => if (x < 10) Some(x + 3) else None
accumulate(0, List(f1, f2, f3))
这会给List[Option[Int]] = List(Some(1), Some(3), Some(6))
。
修改强>
正如Marth指出的那样,有一个专门的功能 - scanLeft
,但是,我想提出一种不同的方法来使用它。将初始值设为输入参数而不是函数:
def accumulate(x: Int, funcs: List[Int => Option[Int]]): List[Option[Int]] =
funcs.scanLeft(Option(x)) {
case (acc, op) => acc.flatMap(op)
}.tail
val f1: Int => Option[Int] = x => if (x < 10) Some(x + 1) else None
val f2: Int => Option[Int] = x => if (x < 10) Some(x + 2) else None
val f3: Int => Option[Int] = x => if (x < 10) Some(x + 3) else None
accumulate(0, List(f1, f2, f3))
答案 1 :(得分:5)
您可以.scanLeft
使用List
Function
,(来自文档):
生成包含应用累积结果的集合 操作员从左到右。
scala> val f1: Int => Option[Int] = x => if (x < 10) Some(x + 1) else None
f1: Int => Option[Int] = <function1>
scala> val f2: Int => Option[Int] = x => if (x < 10) Some(x + 2) else None
f2: Int => Option[Int] = <function1>
scala> val f3: Int => Option[Int] = x => if (x < 10) Some(x + 3) else None
f3: Int => Option[Int] = <function1>
scala> val fList = List(f1,f2,f3)
fList: List[Int => Option[Int]] = List(<function1>, <function1>, <function1>)
scala> val composed = fList.scanLeft((x:Int) => Option(x)) {
case (composedFun, f) => (x:Int) => (composedFun(x)) flatMap f
}.tail
composedFunctions: List[Int => Option[Int]] = List(<function1>, <function1>, <function1>)
scala> composed.map(_(2))
res24: List[Option[Int]] = List(Some(3), Some(5), Some(8))
scala> composed.map(_(8))
res25: List[Option[Int]] = List(Some(9), Some(11), None)
请注意,我必须引入一个初始值(z,这里是(x:Int) => Option(x)
)
您可能希望编写一个函数,该函数采用函数列表并使用funList.head
作为初始值(并在.scanLeft
而不是funList.tail
上调用funList
)。