scan() 的常见模式,我最终不关心状态
Common pattern of scan() where I don't ultimately care about the state
我发现自己经常做以下事情:
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)
在这种情况下,我需要累积 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)
}
}
但是,现在我发现自己也在对列表和向量执行此操作,所以我想知道我是否可以做一些更通用的事情?
您描述的组合器(或至少非常相似的东西)通常称为 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)
这等同于以下内容(使用 Scalaz's implementation of mapAccumLeft
):
xs.mapAccumLeft[Double, Int](1, {
case (acc, i) => (acc + i, i.toDouble / acc)
})._2
mapAccumLeft
returns 一对最终状态和每一步的结果序列,但不需要您指定虚假的初始结果(将被忽略然后丢弃),并且您不必映射整个集合来摆脱状态——您只需取对中的第二个成员。
遗憾的是 mapAccumLeft
在标准库中不可用,但如果您正在寻找一个名称或有关实现的想法,这是一个开始的地方。
我发现自己经常做以下事情:
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)
在这种情况下,我需要累积 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)
}
}
但是,现在我发现自己也在对列表和向量执行此操作,所以我想知道我是否可以做一些更通用的事情?
您描述的组合器(或至少非常相似的东西)通常称为 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)
这等同于以下内容(使用 Scalaz's implementation of mapAccumLeft
):
xs.mapAccumLeft[Double, Int](1, {
case (acc, i) => (acc + i, i.toDouble / acc)
})._2
mapAccumLeft
returns 一对最终状态和每一步的结果序列,但不需要您指定虚假的初始结果(将被忽略然后丢弃),并且您不必映射整个集合来摆脱状态——您只需取对中的第二个成员。
遗憾的是 mapAccumLeft
在标准库中不可用,但如果您正在寻找一个名称或有关实现的想法,这是一个开始的地方。