Предлагаемые решения страдают от того, что они создают промежуточные коллекции или вводят переменные, которые не являются строго необходимыми. В конечном итоге все, что вам нужно сделать, это отслеживать количество шагов итерации. Это можно сделать с помощью запоминания. Полученный код может выглядеть как
myIterable map (doIndexed(someFunction))
Функция doIndexed
оборачивает внутреннюю функцию, которая получает как индекс, так и элементы myIterable
. Это может быть знакомо вам по JavaScript.
Вот способ достижения этой цели. Рассмотрим следующую утилиту:
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)
}
}
Это уже все, что вам нужно. Вы можете применить это, например, следующим образом:
import TraversableUtil._
List('a','b','c').map(doIndexed((i, char) => char + i))
что приводит к списку
List(97, 99, 101)
Таким образом, вы можете использовать обычные функции Traversable за счет обертывания вашей эффективной функции. Накладные расходы - создание запоминающего объекта и счетчика в нем. В противном случае это решение будет таким же хорошим (или плохим) с точки зрения памяти или производительности, как использование неиндексированного map
. Наслаждайтесь!