I have a seq
val seq = Seq(1, 9, 5, 4, 3, 5, 5, 5, 8, 2)
I want to get an average for each adjacent (left and right) numbers, meaning in the above example to have the following calculations:
[(1+9)/2, (1+9+5)/3, (9+5+4)/3, (5+4+3)/3, (4+3+5)/3, (3+5+5)/3, (5+5+5)/3, (5+5+8)/3, (5+8+2)/3, (8+2)/2]
The other examples are:
Seq() shouldBe Seq()
Seq(3) shouldBe Seq(3.0d)
Seq(1, 4) shouldBe Seq(2.5d, 2.5d)
Seq(1, 9, 5, 4, 3, 5, 5, 5, 8, 2) shouldBe Seq(5.0, 5.0, 6.0, 4.0, 4.0, 13.0 / 3, 5.0, 6.0, 5.0, 5.0)
I was able to get: numbers.sliding(2, 1).map(nums => nums.sum.toDouble / nums.length).toSeq
. But it doesn't consider the previous value.
I tried to do it with foldLeft
- it is also cumbersome.
Is there an easy way to do this? What am I missing?
Being honest, this is the kind of problems that I believe are easier to solve using a simple (albeit a bit long) tail-recursive algorithm.
def adjacentAverage(data: List[Int]): List[Double] = {
@annotation.tailrec
def loop(remaining: List[Int], acc: List[Double], previous: Int): List[Double] =
remaining match {
case x :: y :: xs =>
loop(
remaining = y :: xs,
((previous + x + y).toDouble / 3.0d) :: acc,
previous = x
)
case x :: Nil =>
(((previous + x).toDouble / 2.0d) :: acc).reverse
}
data match {
case x :: y :: xs => loop(remaining = y :: xs, acc = ((x + y).toDouble / 2.0d) :: Nil, previous = x)
case x :: Nil => x.toDouble :: Nil
case Nil => Nil
}
}
You can see it running here.