在每次迭代中获取映射中的修改列表

时间:2018-12-23 17:26:02

标签: scala

语言是Scala 假设我有一个Position(x,y)列表,其中包含一些移动指令,并且我想通过一种功能性方法来管理它们之间的冲突,那该怎么办?

示例:

Point a = [x=1,y=1],并有转移到[x=2,y=1]

的指令

Point b = [x=2,y=2],并附有转移到[x=2,y=1]的说明

您的列表为[a,b],然后您想应用该函数移动它们并处理碰撞。因此,在上面的示例中,您应该注意到b与a之间的冲突(b试图转到a的位置)。那是什么代码?

我现在拥有的是:

list.map(position => position.instruction.move())

但是它不能处理碰撞。 我想做

list.map(position => position.instruction.move()(list))

,但是列表仅在地图末尾更新,因此b不会与a冲突。实际上,正在使用初始值验证冲突。它使用的是位置[x = 1,y = 1],而不是新的位置[x = 2,y = 1]。

使用for循环以迭代的方式进行操作很容易,但是如何以功能性的方式进行操作呢?

1 个答案:

答案 0 :(得分:1)

一种选择是使用递归函数检查到目前为止已修改的点并尝试检测碰撞,例如

def moveCollisionAware(l: List[Position]) = {
  @scala.annotation.tailrec
  def move(l: List[Position], acc: List[Position]): Either[String, List[Position]] = l match {
     case Nil => Right(acc)
     case head :: tail =>
       val newPosition = head.move(2, 1)
       if (acc.contains(newPosition))
         Left(s"Moving $head will clash with an existent position")
       else
         move(tail, acc :+ newPosition)
  }

  move(l, List.empty)
}

基本上,这就是您所需要的(也是了解正在发生的事情的一种好方法),一旦您对List API感到更满意,就可以使用foldLeft并实现相同的目的

类似

positions.foldLeft(Right(List.empty[Position]): Either[String, List[Position]]) {
  case (Right(acc), position) =>
    val newPosition = position.move(2, 1)
    if (acc.contains(newPosition))
      Left(s"Moving $position will clash with an existent position")
    else
      Right(acc :+ newPosition)
    case (e @ Left(_), _) => e
}