势在必行与功能的例子

时间:2012-05-03 07:57:30

标签: scala functional-programming imperative-programming

我有一个在命令式和功能性方面实现的方法(我在这里做得最好)。该方法迭代ArrayBuffer [生物],计算每个生物的距离并返回最近或无(如果世界上没有生物,除了'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开始时你有这样的疑虑吗?经过一段时间后,您的功能技能是否得到了极大的改善,并完全击败了强制性方法请发布您的经验。

谢谢!

2 个答案:

答案 0 :(得分:8)

您可以使用collect:

更简单地完成此操作
game.creatures collect { case creature if creature != this => (creature, distanceTo(creature)) }

collect只需PartialFunction,只会返回定义此函数的值,因此不会返回creature == this

还可以替换

case creaturesWithDistance if creaturesWithDistance.isEmpty => None

case Seq() => None

答案 1 :(得分:3)

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

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

这对我来说非常清楚 - 语法噪音很小,特别是与你的命令版本相比。

不幸的是sortByminBy贵,更不幸的是,Scala Collections API中没有“安全”minBy(“安全”意味着它返回{{} 1}}在空列表中调用时为空。不过,以下情况并不太可怕:

Option

因此,在这种情况下,您遇到了Collections API的合法缺点(没有private def closestEnemy = game.creatures.filterNot(_ == this) match { case creatures if creatures.nonEmpty => Some(creatures.minBy(distanceTo)) case _ => None } ),但我个人更喜欢维护此代码而不是命令式版本。


作为脚注:值得注意的是,您可以使用pimp-my-library pattern来“修复”Collections API。只需将以下内容放在某处:

safeMinBy

现在你有一个安全,高效的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