我有一个在命令式和功能性方面实现的方法(我在这里做得最好)。该方法迭代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开始时你有这样的疑虑吗?经过一段时间后,您的功能技能是否得到了极大的改善,并完全击败了强制性方法请发布您的经验。
谢谢!
答案 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
这对我来说非常清楚 - 语法噪音很小,特别是与你的命令版本相比。
不幸的是sortBy
比minBy
贵,更不幸的是,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