So I have the generic method set up consisting of:
You don't need recursion. This could be computed using foldLeft:
elements.foldLeft(0) {
case (accumulator, item) => ...//calculate here next value from previously calculated
//value (accumulator) and current item
}
If you don't want to change the signature you would have to use local function and make that function tail-recursive
def standardDeviation[T](elements: List[T], property: T => Double): Double = {
val values = elements.map(property)
val size = elements.size.toDouble
// this could acually be replaced by values.sum
@scala.annotation.tailrec
def calculateSum(remaining: List[Double], acc: Double): Double = remaining match {
case head :: tail => calculateSum(tail, acc + head)
case Nil => acc
}
val mean = calculateSum(values, 0.0) / size
@scala.annotation.tailrec
def calculateSumOfDiffs(remaining: List[Double], acc: Double): Double = remaining match {
case head :: tail => calculateSumOfDiffs(tail, acc + Math.pow(head - mean, 2.0))
case Nil => acc
}
Math.sqrt(calculateSumOfDiffs(values, 0.0) / (size - 1))
}
When you are doing tail recursive computation you have to somehow pass results-so-far, so if you cannot expose the intermediate results in API, this is the only way.
However, you don't have to implement this using tail rec, but instead use some functional approach instead:
def standardDeviation[T](elements: List[T], property: T => Double): Double = {
val values = elements.map(property)
val size = values.size.toDouble
val mean = values.sum / size
Math.sqrt(values.map(x => Math.pow(x - mean, 2.0)).sum / (size - 1))
}