Suppose we have an array:
val arr = Array[(String, Int)](("A", 3), ("B", 5), ("C", 2), ("D", 7), ("E", 4))
I want to calculate the cumulative sum of the numbers until it exceeds a threshold. Then I want to concatenate a ".p"
suffix for each letter which appeared in the tuples before the threshold.
For instance, let the threshold be 14. In this case I would like an output:
(("A.p", 3), ("B.p", 5), ("C.p", 2), ("D", 7), ("E", 4))
Because 3 + 5 + 2 = 10 < 14
, but 3 + 5 + 2 + 7 = 17 > 14
.
What I tried is the following:
val resIndex = arr.map(_._2).scanLeft(0){_ + _}.tail.takeWhile(_ < 14).length
val resSplit = arr.toList.splitAt(resIndex)
val res = resSplit._1.map(e => (e._1.concat(".p"), e._2)) :: resSplit._2
But I'm sure there is a more efficient and better way to achieve this.
Update!
Thank you for all of your answers! I made a little benchmark to compare the solutions and the most efficient way of doing this was with Assad Mendelson's improved solution.
For the benchmark I used a randomly generated array with 0.5 million of elements and a threshold = 10000
.
For benchmark I used:
def time[A](f: => A) = {
val s = System.nanoTime
val ret = f
println("time: "+(System.nanoTime-s)/1e6+"ms")
ret
}
time {
println("jwvh solution")
arr.foldLeft((0,Array[(String,Int)]())){ case ((sum,ar),(s,i)) =>
if (sum + i < threshold) (sum+i, ar:+((s+".p", i)))
else (sum,ar:+(s,i))
}._2
}