假设我们有一个数组:
val arr = Array[(String, Int)](("A", 3), ("B", 5), ("C", 2), ("D", 7), ("E", 4))
我想计算数字的累积和,直到超过阈值。然后我想连接一个 ".p"
出现在阈值之前的元组中的每个字母的后缀。
例如,让阈值为 14。在这种情况下,我想要一个输出:
(("A.p", 3), ("B.p", 5), ("C.p", 2), ("D", 7), ("E", 4))
因为3 + 5 + 2 = 10 < 14
,但是3 + 5 + 2 + 7 = 17 > 14
.
我尝试过以下内容:
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
但我确信有一种更有效、更好的方法来实现这一目标。
更新!
谢谢大家的回答! 我做了一个小基准来比较解决方案,最有效的方法是使用 Assad Mendelson 的改进解决方案。
对于基准测试,我使用了一个随机生成的数组,其中包含 50 万个元素和 threshold = 10000
.
对于我使用的基准:
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
}
最佳答案
您可以使用 foldLeft
在一次迭代中完成此操作:
val arr =
Array[(String, Int)](("A", 3), ("B", 5), ("C", 2), ("D", 7), ("E", 4))
val threshold = 14
val (values, sum): (List[(String, Int)], Int) =
arr.foldLeft((List.empty[(String, Int)], 0)) {
case ((accumulatedTuples, acc), (str, value)) =>
val sum = acc + value
sum match {
case sum if sum < threshold =>
((s"$str.p", value) :: accumulatedTuples, sum)
case _ => ((str, value) :: accumulatedTuples, acc)
}
}
values.foreach(println)
println(s"Sum: $sum")
产量:
(E,4)
(D,7)
(C.p,2)
(B.p,5)
(A.p,3)
Sum: 10
如果值的顺序很重要,我们需要在末尾添加 .reverse
,或者添加 foldRight
。
关于arrays - 如何在 Scala 中对数组的前几个元素应用函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45059419/