问题描述
val seq = Seq(1,9,5,4,3,8,2)
我想获取每个相邻(左右)数字的平均值,这意味着在上面的示例中进行以下计算:
[(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]
其他示例是:
Seq() shouldBe Seq()
Seq(3) shouldBe Seq(3.0d)
Seq(1,4) shouldBe Seq(2.5d,2.5d)
Seq(1,2) shouldBe Seq(5.0,5.0,6.0,4.0,13.0 / 3,5.0)
我能够得到:numbers.sliding(2,1).map(nums => nums.sum.todouble / nums.length).toSeq
。但它不考虑先前的值。
我尝试用foldLeft
来做-这也很麻烦。
有没有简单的方法可以做到这一点?我想念什么?
解决方法
说实话,我认为使用简单的(尽管有点长)尾递归算法更容易解决这类问题。
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
}
}
您可以看到它正在运行here。
,如果您想要不同大小的滑动窗口,例如4或7或...,该怎么办?面临的挑战是如何积累(1),(1,2),2,3),3,4),...
和尾随的...,(6,7,8,9),(7,(8,(9)
。
def windowAvg(input: Seq[Int],windowSize: Int): Seq[Double] =
if (input.isEmpty || windowSize < 1) Seq()
else {
val windows = input.sliding(windowSize).toSeq
val buildUp = windows.head.inits.toSeq.tail.reverse.tail
val tailOff = windows.last.tails.toSeq.tail.init
(buildUp ++ windows ++ tailOff).map(x => x.sum.toDouble / x.length)
}
如果您确实需要精简结果中的开头和结尾的单数条目,那么我将其留给读者练习。
,我通过foldLeft
遇到的麻烦的解决方案(没有火箭科学)
def adjacentAverage(numbers: Seq[Int]): Seq[Double] = numbers.foldLeft(("x",Seq[Double](),0)) {(acc,num) => acc._1 match {
case "x" => if (numbers.isEmpty) ("x",Seq(),acc._3 + 1) else if (numbers.length == 1) ("x",Seq(num.toDouble),acc._3 + 1) else (num.toString,acc._2 :+ ((num.toDouble + numbers(acc._3 + 1).toDouble) / 2.0),acc._3 + 1)
case _ => (num.toString,try {acc._2 :+ ((acc._1.toDouble + num.toDouble + numbers(acc._3 + 1).toDouble) / 3.0)} catch {case e: IndexOutOfBoundsException => acc._2 :+ ((acc._1.toDouble + num.toDouble) / 2.0) },acc._3 + 1)
}}._2