The proposed solutions are related to the fact that they create intermediate collections or introduce variables that are not strictly necessary. Ultimately, all you have to do is keep track of the number of iteration steps. This can be done using memoizing. The resulting code may look like
myIterable map (doIndexed(someFunction))
doIndexed -Funk wraps an internal function that receives both the index and myIterable elements. This may be familiar to you with JavaScript.
Here is a way to achieve this. Consider the following utility:
object TraversableUtil { class IndexMemoizingFunction[A, B](f: (Int, A) => B) extends Function1[A, B] { private var index = 0 override def apply(a: A): B = { val ret = f(index, a) index += 1 ret } } def doIndexed[A, B](f: (Int, A) => B): A => B = { new IndexMemoizingFunction(f) } }
That is all you need. You can apply this, for example, as follows:
import TraversableUtil._ List('a','b','c').map(doIndexed((i, char) => char + i))
leading to a list
List(97, 99, 101)
This way you can use regular Traversable functions by porting your efficient function. Overhead is the creation of a memoizing object and a counter in it. Otherwise, this solution will be as good (or bad) in terms of memory or performance as using a unindexed map . Enjoy it!
Matt Brasen May 09 '12 at 9:41 a.m. 2012-05-09 09:41
source share