Scala-fy是一个java函数吗?

时间:2011-02-18 00:45:53

标签: scala

我最近将我的作业从Java改为Scala。但是,它仍然看起来像java。 例如,下面的函数在范围树上搜索,在那里我做了一些“isInstanceOf”检查。

然而 - 用“匹配”替换它们似乎只会占用更多空间。任何人都可以对如何“scalify”这段代码提出一些改进吗?

def rangeSearch2D(treeRoot: Node, lower: Data2D, upper: Data2D, 
         visited: Visited): Seq[Data2D] = {

    if (treeRoot == null) {
      // return empty list
  return Vector()
}
// increment visit count
if (visited != null)
  visited.visit2D(treeRoot)

var results = ArrayBuffer[Data2D]()

// Find nearest common ancestor with value between lower.x and upper.x
var common: Node = commonAncestor(treeRoot, lower, upper, visited)

if (common.isInstanceOf[LeafNode]) {
  return Vector(common.asInstanceOf[LeafNode].data)
}

/** Common non-leaf node, must process subtree */
/** Process left subtree */
var current = common.left

while (!current.isInstanceOf[LeafNode]) {
  if (visited != null)
    visited.visit2D(current)

  //Find a path from current to lower.x
  if (lower.x <= current.midRange) {
    results.appendAll(rangeSearch1D(current.right.subTree, 
                        lower, upper, visited))
    current = current.left
  } else {
    current = current.right
  }
}
//Check if current leaf node is in range
if (inRange(current, lower, upper)) {

  results.append(current.asInstanceOf[LeafNode].data)
}
/** Process right subtree */
current = common.right

while (!current.isInstanceOf[LeafNode]) {
  if (visited != null)
    visited.visit2D(current)

  //Find a path from current to upper.x
  if (upper.x >= current.midRange) {

    results.appendAll(rangeSearch1D(current.left.subTree, 
                        lower, upper, visited))
    current = current.right
  } else {
    current = current.left
  }
}
//Check if current leaf node is in range
    if (inRange(current, lower, upper)) {
      results.append(current.asInstanceOf[LeafNode].data)
    }

    return results
  }

3 个答案:

答案 0 :(得分:5)

好吧,首先你可以摆脱null,用null替换可能Option的参数。在代码中,然后更改

if (visited != null)
  visited.visit2D(x)

visited foreach (_ visit2D x)

while循环都可以用递归函数替换。您可以将它作为递归函数中的不可变累加器参数传递给而不是将结果添加到可变变量中。

如果Node有一个提取器,您可以使用案例防护来进行midrange测试。不会增加太多,但更具惯用性。

我感觉两个while循环都可以包含在一个递归中,但我没有考虑足够的算法来决定它。如果是这样,您可以提前common返回。

顺便说一下,那里有一个错误,因为该范围内可能没有共同的祖先。

答案 1 :(得分:3)

对于Scala-fy上面的代码,您可以采取一些相当一般的步骤:

  • 减少 if 语句的数量并替换强制转换和 使用模式匹配进行类型测试

  • 用。删除 while 语句 递归函数/方法或 库方法(如折叠)

  • 通过传递消灭变种 累加器转换为函数/方法 调用并指定结果以恢复最终累积

  • 使用值减少分配 通过多块语句返回,例如 if 尝试捕获

  • 使用选项类型

  • 消除空值
  • 取消 return 关键字以防范 反对遗漏的排列

  • 如果执行No-Op,则只留下 else 块/语句(如果没有,编译器应该从如果中捕获损坏的分配其他

  • 如果可能,使用提取器在模式匹配中轻松分解层次结构。

  • 如果代码没有读好重构并引入命名良好的辅助函数/方法

答案 2 :(得分:2)

第一步可能是这样的,但我确信有更多的机会(例如以较小的步骤打破方法[并避免像currentN这样的东西],找到统一loop0loop1,这是丑陋的,用不可变的结构替换ArrayBuffer,使访问过Option

  def rangeSearch2D(treeRoot: Node, lower: Data2D, upper: Data2D, visited: Visited): Seq[Data2D] = 
  if (treeRoot == null) Vector() // return empty list
  else {

    // increment visit count
    if (visited != null)
      visited.visit2D(treeRoot)

    val results = ArrayBuffer[Data2D]()

    // Find nearest common ancestor with value between lower.x and upper.x
    val (current0,current2) = commonAncestor(treeRoot, lower, upper, visited) match {
      case leafNode:LeafNode => return Vector(leafNode.data)
      case common => (common.left, common.right)
    }     

    def loop0(current: Node):Node = current match {
      case _:LeafNode => current
      case _ =>  if (visited != null) visited.visit2D(current)
        if (lower.x <= current.midRange) {
          results.appendAll(rangeSearch1D(current.right.subTree, 
                                          lower, upper, visited))
          current.left
        } else current.right
    }

    val current1 = loop0(current0)


    //Check if current leaf node is in range
    if (inRange(current1, lower, upper))  results.append(current1.asInstanceOf[LeafNode].data)

    def loop1(current: Node):Node = current match {
      case _:LeafNode => current
      case _ =>  if (visited != null) visited.visit2D(current)
        if (upper.x >= current.midRange) {
          results.appendAll(rangeSearch1D(current.left.subTree, 
                                          lower, upper, visited))
          current.right
        } else current.left
    }

    val current3 = loop1(current2)

    //Check if current leaf node is in range
    if (inRange(current3, lower, upper)) 
      results.append(current3.asInstanceOf[LeafNode].data)

    results
  }