给定一个将索引与值相关联的映射,当可以组合在一起的值的数量不能超过某个限制值时,如何创建一个单独的映射,以累积高于特定阈值的值?
例如,给定这样的映射:
val raw = Map(0 -> 2, 1 -> 1, 2 -> 2, 3 -> 0, 4 -> 1, 5 -> 2)
将这些值一起分组 2,但每个分组最多只能包含2个值的总和,这样如果第一个值为> = 2,则分组将包含单个值。相反,如果第1个值小于2,则分组的大小为2,其值由第1个值和第2个值组成。
在上面的映射中执行该操作会产生该组索引值的映射,例如
Map(0 -> 2, 1 -> 3, 2 -> 1, 3 -> 2) // Result
显然,以非功能性方式执行此操作的方式如下:
var c = 0
var sortedIndex = 0
var acc: Map[Int, Int] = Map() // Result accumulator
val limit = 2 // Anything larger will be forced into the next group
while (c < raw.size) {
if (raw(c) >= limit) {
acc = acc ++ Map(sortedIndex -> raw(c))
c = c + 1
} else {
acc = acc ++ Map(sortedIndex -> raw(c) + raw(c + i)
c = c + 2
}
sortedIndex = sortedIndex + 1
}
acc
我如何在功能上这样做?即,不可变状态,减少了我对循环的使用。 (我知道循环不是&#34;死了&#34;在FP中,只是试图强化一个用例,我可以在不使用循环的情况下逃脱。)
答案 0 :(得分:1)
我认为你不需要使用Map来解决这个问题。由于地图的关键是简单的索引。任何情况下,您的问题的工作如下:
val testLimit = 2 // Update the constants as required
val takeUpto = 2
def accumulator(input: List[Int], output: List[Int] = List.empty[Int]): List[Int] = {
input match {
case Nil => output // We have reached at the end of the input
case head :: tail if head >= testLimit => accumulator(tail, output :+ head)
case m =>
val (toSum, next) = m.splitAt(takeUpto)
accumulator(next, output :+ toSum.sum)
}
}
// Map(0 -> 2, 1 -> 3, 3 -> 1, 4 -> 2) // Result
// val raw = Map(0 -> 2, 1 -> 1, 2 -> 2, 3 -> 0, 4 -> 1, 5 -> 2) equivalent is List(2, 1, 2, 0, 1, 2)
println(accumulator(List(2, 1, 2, 0, 1, 2)))