我发现自己经常做以下事情:
val adjustedActions = actions.scanLeft((1.0, null: CorpAction)){
case ((runningSplitAdj, _), action) => action match {
case Dividend(date, amount) =>
(runningSplitAdj, Dividend(date, amount * runningSplitAdj))
case s @ Split(date, sharesForOne) =>
((runningSplitAdj * sharesForOne), s)
}
}
.drop(1).map(_._2)
Run Code Online (Sandbox Code Playgroud)
runningSplitAdj在这种情况下,我需要积累,以便纠正动作列表中的股息.在这里,我scan用来维护我需要的状态以纠正动作,但最后,我只需要动作.因此,我需要在状态中使用null作为初始操作,但最后,删除该项并映射所有状态.
是否有更优雅的方式来构建这些? 在RxScala Observables的上下文中,我实际上创建了一个新的运算符(在RxJava邮件列表的一些帮助之后):
implicit class ScanMappingObs[X](val obs: Observable[X]) extends AnyVal {
def scanMap[S,Y](f: (X,S) => (Y,S), s0: S): Observable[Y] = {
val y0: Y = null.asInstanceOf[Y]
// drop(1) because scan also emits initial state
obs.scan((y0, s0)){case ((y, s), x) => f(x, s)}.drop(1).map(_._1)
}
}
Run Code Online (Sandbox Code Playgroud)
但是,现在我发现自己也在对Lists和Vectors进行操作,所以我想知道我能做些更普遍的事情吗?
您正在描述的组合子(或至少非常相似的组合)通常被称为mapAccum.采用以下简化用法scanLeft:
val xs = (1 to 10).toList
val result1 = xs.scanLeft((1, 0.0)) {
case ((acc, _), i) => (acc + i, i.toDouble / acc)
}.tail.map(_._2)
Run Code Online (Sandbox Code Playgroud)
这相当于以下(使用Scalaz的实现mapAccumLeft):
xs.mapAccumLeft[Double, Int](1, {
case (acc, i) => (acc + i, i.toDouble / acc)
})._2
Run Code Online (Sandbox Code Playgroud)
mapAccumLeft 在每一步返回一对最终状态和一系列结果,但它不需要你指定一个虚假的初始结果(只会被忽略然后丢弃),你不必映射整个集合摆脱了状态 - 你只需要成对的第二个成员.
遗憾的mapAccumLeft是,标准库中没有这种功能,但如果您正在寻找名称或有关实施的想法,那么这是一个可以开始的地方.
| 归档时间: |
|
| 查看次数: |
164 次 |
| 最近记录: |