4

命令的および機能的な方法で実装されたメソッドがあります(ここで最善を尽くしました)。このメソッドは ArrayBuffer[Creature] を反復処理し、各クリーチャーまでの距離を計算し、最も近いものまたは None を返します (「これ」以外のクリーチャーがワールドに存在しない場合)。

必須:

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)
  }

機能コードはあまり明白ではないように見えます (おそらく単純化できますが、方法はわかりません)。1 か月でその場で読むことができるかどうかはわかりません。私の質問は、習慣の問題ですか、それともこの特定のケースには機能的ではありませんか? Scalaを始めたとき、あなたはそのような疑問を持っていましたか? しばらくすると、機能的スキルが大幅に向上し、命令型アプローチを完全に打ち負かしましたか? 体験談を投稿してください。

ありがとう!

4

2 に答える 2

8

You can do this simpler by using collect:

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

collect takes a PartialFunction and will only return values at which this function is defined, so creature == this will not be returned.

And also you can replace

case creaturesWithDistance if creaturesWithDistance.isEmpty => None

with

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

主な目標が読みやすさである場合、以下はコードと同じ出力を提供します。

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

これは私には非常に明確に思えます。特に命令型のバージョンと比較して、構文上のノイズはほとんどありません。

残念ながらsortByは よりも高価でありminBy、さらに残念なことに、Scala Collections API には「安全」がありません(「安全」とは、空のリストで呼び出されたときに空の をminBy返すことを意味します)。Optionただし、以下はそれほどひどいものではありません。

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

したがって、この場合、コレクション API の正当な欠点 (いいえsafeMinBy) に遭遇しましたが、個人的には、命令的なバージョンよりもこのコードを維持することを強く望んでいます。


脚注として: pimp-my-library パターンを使用して Collections 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 に答える