4

我有一个以命令式和功能性(我在这里尽了最大努力)方式实现的方法。该方法遍历 ArrayBuffer[Creature],计算到每个生物的距离并返回最近的或无(如果世界上没有生物,除了“this”)。

至关重要的:

private def closestEnemy: Option[Creature] = {
  var closest: Option[Creature] = None
  var distanceToClosest = Int.MaxValue

  for(creature <- game.creatures if creature != this) {
    val distance = distanceTo(creature)

    if(distance < distanceToClosest) {
      closest = Some(creature)
      distanceToClosest = distance
    }
  }

  closest
}

功能:

private def closestEnemy: Option[Creature] =
  game.creatures filter { _ != this } map { creature => (creature, distanceTo(creature)) } match {
    case creaturesWithDistance if creaturesWithDistance.isEmpty => None
    case creaturesWithDistance => Some(creaturesWithDistance minBy { _._2 } _1)
  }

功能代码看起来不那么明显(可能可以简化,但我不知道如何简化)而且我不确定我是否能够在一个月内快速阅读它。我的问题是习惯或功能问题不适合这种特殊情况吗?刚开始使用 Scala 的时候,你有没有这样的疑惑?一段时间后,您的功能技能是否有很大提高并完全击败了命令式方法?请发表您的经验。

谢谢!

4

2 回答 2

8

您可以使用 collect 更简单地执行此操作:

game.creatures collect { case creature if creature != this => (creature, distanceTo(creature)) }

collect接受 aPartialFunction并且只会返回定义此函数的值,因此creature == this不会返回。

你也可以更换

case creaturesWithDistance if creaturesWithDistance.isEmpty => None

case Seq() => None
于 2012-05-03T08:29:09.133 回答
3

如果您的主要目标是可读性,则以下内容将提供与您的代码相同的输出:

private def closestEnemy =
  game.creatures.filterNot(_ == this).sortBy(distanceTo).headOption

这对我来说似乎非常清楚 - 几乎没有语法噪音,特别是与您的命令式版本相比。

不幸sortBy的是比 更昂贵minBy,更不幸的minBy是,Scala Collections API 中没有“安全”(其中“安全”意味着它Option在空列表上调用时返回一个空的)。不过,以下情况并不太可怕:

private def closestEnemy = game.creatures.filterNot(_ == this) match {
  case creatures if creatures.nonEmpty => Some(creatures.minBy(distanceTo))
  case _ => None
}

因此,在这种情况下,您遇到了 Collections API 的合法缺点(否safeMinBy),但我个人仍然更喜欢维护此代码而不是您的命令式版本。


作为脚注:值得注意的是,您可以使用pimp-my-library 模式来“修复”集合 API。只需将以下内容放在范围内:

implicit def makeSeqSafer[A](xs: Seq[A]) = new {
  def safeMinBy[B: Ordering](f: A => B) =
    if (xs.isEmpty) None else Some(xs.minBy(f))
}

现在你有了一个安全、高效的minBy

scala> List(1, 2, 3).safeMinBy(_ * 2)
res0: Option[Int] = Some(1)

scala> List.empty[Int].safeMinBy(_ * 2)
res1: Option[Int] = None

在你的情况下:

private def closestEnemy =
  game.creatures.filterNot(_ == this).safeMinBy(distanceTo)
于 2012-05-03T09:58:20.767 回答