Monday, 12 October 2009

Scala: C style iterate function for building lists

In my previous post, I used a forloop function for creating a List from a sort of c-like for loop

val rets = forloop(today)(d => d >= _start && d >= limit)(d => d - 7.days) {
day =>
val ret = getReturn(day - 7.days, day)
ret.get // might throw Exception (same as c# code)
}


I liked the fact that I could use break and continue semantics in the loop although I didn't need it in the algorithm.

But perhaps foreach is/was trying to do too much, effectively (a) producing a list of dates (etc) and then (b) for each date in the List calculating another value (a Double) to return in a list. Of course (b) is just the map function. So here's another function that I've called iterateFor which only does (a). Using it to replace the code above gives:


val dates = iterateFor(today)(d => d >= _start && d >= limit)(d => d - 7.days)
val rets = dates.map(d => getReturn(d - 7.days, d).get)


I was hoping to find something already built it to the scala libraries that would do what iterateFor does . As Daniel pointed out in the comments there is Iterator.iterate:

def iterate [T](start : T)(f : (T) => T) : Iterator[T]


and if you use takeWhile on the Iterator then the implementation of iterateFor is simple:


def iterateFor[T]
(init: T)
(cond: T => Boolean)
(next: T => T)
: List[T] =
{
Iterator.iterate(init)(next) takeWhile cond toList
}


Or it can be implemented as a recursive function like this:


def iterateFor[T]
(init: T)
(cond: T => Boolean)
(next: T => T)
: List[T] =
{
def _iterateFor(currentResults: List[T])(loopcounter: T) : List[T] = {
if (cond(loopcounter)) {
val newResults = loopcounter :: currentResults
_iterateFor(newResults)(next(loopcounter))
} else {
currentResults
}
}
_iterateFor(List())(init).reverse
}


I suspect that there are plenty of little while loop type algorithms that use vars that could be replaced by iterateFor (or forloop).
Post a Comment