First, I’m assuming calc1/2/3 are all pure functions (i.e. have no side effects, but only calculate and return a Double
). If this is not the case, you should provide their implementation.
In your code, you probably want everything after the first if
in an else
block, otherwise the code in the if
will never have an effect.
About the main loop:
You are reducing a list of elements to a single value, using an accumulation rule. This is a typical use case for a fold operation. The foldLeft
method on list takes a start value and a function that generates the next value from the current value and current list element, going through the whole list this way.
For example, to sum a list of integers, you can write
List(1,2,3).foldLeft(0)((acc, i) => acc + i)
Starting with value 0, the function is called with that value and the next list element to give the sum of all the values in the list.
For your method, it get’s a bit more complicated, as you have to handle the first list element differently. Also, you need two intermediate values (old
and res
).
So as start value, you can use a tuple, consisting of the first list element and the result of the calc1 method. Your fold function will then receive a Double
and an E
as accumulator value.
val startValue = (lengths.head, calc1(length1, lengths.head))
As we now have the first value already, the fold function should not handle it again, so we use lengths.tail.foldLeft(...)
: tail
gives the list with the head removed.
In the function passed to foldLeft
, your calc2
method must be called. But as our start value is a tuple of (E, Double)
, we also must return such a tuple, so we always also pass on the current length.
(acc, length) =>
// acc is the tuple of previous length and calculation result
acc match {
//pass on current element and calc result
case (old, acc) => (length, calc2(old, length, acc))
}
The result of the fold will be a tuple with the last element and the value of your res
after your loop. So we have everything we need to call calc3
. Your last two lines can be made functional by simply removing the assignment and the second line:
res += calc3(old, length2, res)
res
// is same as returning result of summing directly:
res + calc3(old, length2, res)
Putting it all together:
def length(length1: E, length2: E, lengths: List[E]): Double = {
if (lengths.isEmpty) {
calc1(length1, length2)
} else {
val startValue = (lengths.head, calc1(length1, lengths.head))
val (last, res) = lengths.tail.foldLeft(startValue) { (acc, length) =>
acc match {
case (old, acc) => (length, calc2(old, length, acc))
}
}
res + calc3(last, length2, res)
}
}
Now, depending on what your calc methods do, this could be made simpler. So if you post your E
type and the calc methods, I’ll take a look.