What's the fastest/simplest way to calculate a moving Average in Kotlin?
Kotlin 1.2 will introduce a sliding window which you can combine with average
obviously.
val data = listOf(1,2,5,6,2,7,8,5,9)
// 3 "period" moving average
val movingAverage = data.windowed(3,1,List<Int>::average)
// OR
val movingAverage = data.windowed(3,1) { it.average() }
Until then you would have to introduce your own sliding sequence.
class SlidingSequence<out T>(val source: Iterable<T>,
val slideSize: Int,
val slideStep: Int) : Sequence<List<T>> {
override fun iterator(): Iterator<List<T>> = object : AbstractIterator<List<T>>() {
private val iterator = if (slideSize > 0) source.iterator() else emptyList<T>().iterator()
private var buffer = listOf<T>()
override fun computeNext() = when {
iterator.hasNext() -> {
buffer = buffer.drop(slideStep).let {
it + iterator.asSequence().take(slideSize - it.size)
}
setNext(buffer)
}
else -> done()
}
}
}
fun <T> Iterable<T>.windowed(size: Int,
step: Int = 1): Sequence<List<T>> {
return SlidingSequence(this, size, step)
}
// and then you can do
val data = listOf(1,2,5,6,2,7,8,5,9)
// 3 "period" moving average
val movingAverage = data.windowed(3).map(List<Int>::average)
PS. I haven't looked at the code of Kotlin 1.2 windowed
implementation, but since the function takes an immediate transform, I'm guessing the result is not lazy, where in the self implemented case above it's a lazy result, so you need to actually enumerate the sequence with something like .toList()
to get the actual values.