English 中文(简体)
插图。 试图在经过的参数中修改清单(显然是不可能的)
原标题:Recursion in scala. Trying to modify List in passed parameter(which is not possible obviously)

Java 我有这样的方法。

    public static void digPackageLines( List<PkgLine> pkgLineList, Tree treeParam ) {

    if ( findPkgLineTreeExist( treeParam ) == false ) {
        for ( Tree tree : findParents( treeParam ) ) {
            digPackageLines( pkgLineList, tree );
        }

    } else {

        for ( PkgLineTree pkgLineTree : findPkgLineTreeByTree( treeParam ) ) {
            pkgLineList.add( pkgLineTree.pkgLineId );

        }
    }
}

这将包含一个清单,并通过在清单中增加kg。 现在,由于所有参数都是阀的,无法加以修改,因此不可能做到这一点。

这是我迄今为止所做的。

def digPackageLines(pkgLineList : Seq[ PkgLine ], tree_id : Long) : Unit = {

    if ( PkgLineTree.findPkgLineTreeExist(tree_id) == false ) {  //tree is parent if no lines found

        Tree.findParents(tree_id) map {
            tree =>
                digPackageLines(pkgLineList, tree.tree_id.get) //dig further into tree
        }

    } else { //found lines

        PkgLineTree.findByTreeId(tree_id) map {
            pkgLineTree =>
                PkgLine.findById(pkgLineTree.pkg_line_id).get //add this line to pkgLineList somehow
        }
    }
}

因此,我不喜欢做什么。 我正在研究尾部复习辅导,但只是基本内容,只是处理数字。 我是否需要从休养职能中恢复一份名单? 职能可以产生副作用,因此我猜测这是唯一的办法。

我的另一个主要问题是增列目标。 显然,我需要一份名单副本,然后将物体贴上该名单。 问题在于,我无法在 lo中产生新的变数。 我确信,这样做非常容易。 感谢任何帮助。

**EDIT**

最后,我已经这样做。

val pkgLineList : Seq[ (PkgLine, Tree) ] = User.findUserJoinAllAcl(10) flatMap {
        user =>
            PkgLine.digPackageLines(Vector[ (PkgLine, Tree) ](), user._2.tree_id)
    }

这是否正确。 我已经修改了返回遗体的方法。 但只有差别。 Seems to be working good.

最佳回答

在Schala,有可变的收藏和不可变的收集。 优先选择是使用不可改变的,但根据具体情况,你总是可以回头.。

在这里,你希望通过可互换的<代码>List来加以解释,这是不理想的,因为附录操作是O(n)。 预支的是O(1)。 解决这个问题的一个典型办法是使用<代码>List和预支和最终使用reverse,以取得预期结果。

You can use the mutable ListBuffer which can be converted to a list in a O(1) operation:

import collection.mutable.ListBuffer

@annotation.tailrec // check that this is optimized for tail call
def digPackageLines(pkgLineList: ListBuffer[PkgLine], tree_id: Long): Unit = {

  if (PkgLineTree.findPkgLineTreeExist(tree_id) == false) {
    Tree.findParents(tree_id) map { tree =>
      digPackageLines(pkgLineList, tree.tree_id.get)
    }
  } else { //found lines and return result as List
    PkgLineTree.findByTreeId(tree_id) map { pkgLineTree =>
      pkgLineList += PkgLine.findById(pkgLineTree.pkg_line_id).get
    }
  }
}

But let s see how to do this in a more "functional" way. Let use an immutable Vector which has amortized O(1) append. The function will return the combined results, since the input cannot be mutated:

def digPackageLines(pkgLines: Vector[PkgLine], tree_id: Long): Vector[PkgLine] ={

  if (PkgLineTree.findPkgLineTreeExist(tree_id) == false) {
      val parentTrees = Tree.findParents(tree_id)
      parentTrees.foldLeft(pkgLines){ (lines, tree) =>
        digPackageLines(lines, tree.tree_id.get)
      }
    }
  } else { //found lines and return result as List
    val additions = PkgLineTree.findByTreeId(tree_id) map { pkgLineTree =>
      PkgLine.findById(pkgLineTree.pkg_line_id).get
    }
    pkgLines ++ additions
  }
}

同样的免责声明也适用于(N.b. In t. ),因此可能出现错误。

问题回答

Scala s default collections are immutable, which means you can t make changes to them. However, there are a separate package of mutable collections. The mutable variant of a List is a ListBuffer, which is available in the scala.collection.mutable package. Using a ListBuffer you would be able to do:

pkgLineList += PkgLine.findById(pkgLineTree.pkg_line_id).get

这将是对 your版本的直接翻译。 然而,你可能想做的是,以更直截了当的方式来重写。 它看上去你通过一些分行的数据结构来做些什么,并将结果列入一个清单。 你们可以非常容易地用原始的休养方式来重写:

def digPackageLines(tree_id : Long) : Seq[PkgLine] = {
  def _digPackageLines(acc : List[PkgLine], tree_id : Long) : List[PkgLine] = {
    // Base case 
    if (PkgLineTree.findPkgLineTreeExist(tree_id)) {
      PkgLineTree.findByTreeId(tree_id) map {
        pkgLineTree =>
            PkgLine.findById(pkgLineTree.pkg_line_id).get
      } ::: acc
    } else {
      // We use flatMap instead of Map to concatenate the results of the recursive calls
      Tree.findParents(tree_id) flatMap { tree =>
        digPackageLines(pkgLineList, tree.tree_id.get)
      } ::: acc
    }
  }

  // Call our helper function with an empty list
  _digPackageLines(List[PkgLine](), tree_id)
}

(不适用。)

The key point to note is that we use an accumulator to store the results of our list as we go along. However, note that this isn t tail recursive, since we re branching at each stage and having to concatenate the results.





相关问题
Recursive same-table query in SQL Server 2008

I have the following table in a SQL Server 2008 database: Id Name ParentFolder -- ---- ------------ 1 Europe NULL 2 Asia NULL 3 Germany 1 4 UK 1 5 China ...

Finding a class within list

I have a class (Node) which has a property of SubNodes which is a List of the Node class I have a list of Nodes (of which each Node may or may not have a list of SubNodes within itself) I need to be ...

Selecting records during recursive stored procedure

I ve got a content management system that contains a hierarchical structure of categories, with sub-categories subject to different ordering options at each level. Currently, that s retrieved by a (...