在功能上攻击分组值集

时间:2018-02-05 01:20:28

标签: scala functional-programming

给定一个将索引与值相关联的映射,当可以组合在一起的值的数量不能超过某个限制值时,如何创建一个单独的映射,以累积高于特定阈值的值?

例如,给定这样的映射:

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中,只是试图强化一个用例,我可以在不使用循环的情况下逃脱。)

1 个答案:

答案 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)))