多个scala调用比尾递归自定义函数更快

时间:2016-02-09 16:27:19

标签: list scala recursion

我希望这是这个问题的正确位置。

我编写了一些代码来改进2D模拟的碰撞检测。该算法的一部分是将对象列表与它们所属的特定2D区域相关联。函数f: (Seq[Box], Seq[T]) => Map[Box, Seq[T]]

我首先使用原生Scala函数实现它,例如mapgroupBy,...但是我还需要它来返回空Seq[T]groupBy的框不这样做,所以我写了一个递归函数,在我看来应该比前一个更快(这可能是我不知道更好的方法,但这不是主要问题)。

事实证明,我的尾递归实现在计算上比使用Scala库的实现慢,它的执行时间比另一个(基准)更快。我不明白为什么,有人能指出我的原因吗?

def spreadAcrossFast[T](
  nodes: Seq[Box],
  objects: Seq[T]
) = {
  // I create the pairs (reference box, objects that intersects the box)
  // intersects() is called nodes.size * object.size times
  val assigned = for (
    b ← nodes;
    s ← objects if intersects( b, s )
  ) yield ( b, s )

  // Group by Box and clean the format of the association above
  assigned
    // Should be O(n*Log n)
    .groupBy( _._1 )
    // Maximum nodes.size iterations
    .map { x ⇒
      // Can consider objects.size / nodes.size iterations
      ( x._1, x._2.map( _._2 ) )
    }
}

def spreadAcrossSlow[T](
  nodes: Seq[Box],
  objects: Seq[T],
  compact: Boolean = true   // If compact == true, don't include in the output Box that
) = {                       // have empty content
  @tailrec
  def loop( boxes: Seq[Box], acc: Map[Box, Seq[T]] ): Map[Box, Seq[T]] = boxes match {
    // End of the boxes, return the accumulator
    case Nil ⇒ acc

    // Get the objects that intersect the box and add them to the accumulator
    case b +: bs ⇒
      // Every call it goes through objects.size items
      // intersects() is called nodes.size * object.size times
      val objInBox = objects.filter( intersects( b, _ ) )
      val newAcc = if ( objInBox.isEmpty && compact ) acc else acc + ( ( b, objInBox ) )
      loop( bs, newAcc )
  }

  // nodes.size iterations
  loop( nodes, Map.empty[Box, Seq[T]] )
}

SeqList的一个实例。

从我的观点来看,spreadAcrossFast的迭代次数多于spreadAcrossSlow,而最昂贵的操作intersects()被称为相同的次数,nodes.size * objects.size < / p>

更新:即使使用也没有运气(但代码更清晰):

def spreadAcrossSlow[T: SpatialIndexable](
  nodes: Seq[Box], objects: Seq[T], compact: Boolean
): Map[Box, Seq[T]] = {
  val acc = scala.collection.mutable.HashMap[Box, Seq[T]]()

  for ( b ← nodes ) {
    val objInBox = objects.filter( intersects( b, _ ) )
    if ( objInBox.nonEmpty || !compact ) acc += ( ( b, objInBox ) )
  }

  acc.toMap
}

0 个答案:

没有答案