2015-03-09 2 views
3

я считаю себя постоянно делать такие вещи, как следующее:Общий шаблон сканирования(), где я в конечном счете не заботиться о состоянии

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 наблюдаемых, я на самом деле сделал новый оператор, чтобы сделать это (после некоторой помощи из списка рассылки 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) 
    } 
} 

Однако теперь я считаю себя делать это в списки и векторы тоже, так что Интересно, есть ли что-то более общее, что я могу сделать?

ответ

5

Комбинатор, который вы описываете (или, по крайней мере, что-то очень похожее), часто называют 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 возвращает пару конечного состояния и последовательность результатов на каждом но вам не нужно указывать ложный исходный результат (который будет просто проигнорирован и затем опущен), и вам не нужно отображать всю коллекцию, чтобы избавиться от состояния - вы просто берете второй член пары.

К сожалению, mapAccumLeft не доступен в стандартной библиотеке, но если вы ищете имя или идеи относительно реализации, это место для начала.

Смежные вопросы