Scala-fy 一个 java 函数?

发布于 2024-10-18 06:04:31 字数 1875 浏览 1 评论 0原文

我最近将我的任务从 Java 转到了 Scala。然而,它看起来仍然像java。 例如,下面的函数在范围树上进行搜索,并在其中进行一些“isInstanceOf”检查。

然而,用“匹配”替换它们似乎只会占用更多空间。谁能就如何“扩展”这段代码提出一些改进建议?

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
  }

I've recently switched my assignment from Java to Scala. However, it still looks like java.
For example, the function below does a search on a range tree, and inside there I do some "isInstanceOf" checks.

However - replacing them with "match" seems like it would only take up more space. Can anyone suggest some improvements on how to "scalify" this code?

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
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寒冷纷飞旳雪 2024-10-25 06:04:31

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

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

visited foreach (_ visit2D x)

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

如果Node有提取器,您可以使用外壳保护来进行中端测试。没有增加太多,但更惯用。

我感觉两个 while 循环都可以包含在一个递归中,但我还没有充分考虑算法来决定这一点。如果是这样,您可能会获得common提前回报。

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

Well, first you can get rid of null, replacing the parameters that might be null with Option. In the code, you then change

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

with

visited foreach (_ visit2D x)

Both while loops can be replaced with recursive functions. Instead of adding the result to a mutable variable, you can pass it as an immutable accumulator parameter in the recursive function.

If Node has an extractor, you could use a case guard to make the midrange test. Doesn't add much, but is more idiomatic.

I get the feeling that both while loops can be subsumed into a single recursion, but I haven't considered the algorithm enough to decided about that. If so, you could get away with the common early return.

By the way, there's a bug there, since there might not be a common ancestor within the range.

放我走吧 2024-10-25 06:04:31

要对上面的代码进行 Scala 化,您可以采取一些相当通用的步骤:

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

  • 消除 while 语句
    递归函数/方法或
    库方法(例如折叠)

  • 通过传递消除变量
    累加器到函数/方法中
    调用并分配结果以恢复最终累加

  • 通过使用值来减少分配
    iftry catch

    等多块语句返回

  • 使用Option类型消除空值

  • 消除return关键字来保护
    防止丢失排列

  • 仅在执行空操作时省略 else 块/语句(编译器应捕获来自 if 且没有 else

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

  • 如果代码读起来不好重构并引入命名良好的帮助函数/方法

To Scala-fy the code above there are a few fairly general steps you could take:

  • Reduce the number of if statements and replace casts and
    type tests with pattern matching

  • Eliminate while statements with
    recursive functions / methods or
    library methods (such as folds)

  • Eliminate vars by passing
    accumulators into function / method
    calls and assign the result to recover the final accumulation

  • Reduce assignments by using values
    returned by multi-block statements such as if and try catch

  • Eliminate nulls using Option types

  • Eliminate the return keyword to guard
    against missing permutations

  • Only leave out an else block / statement if it performs a No-Op (the compiler should catch broken assignments from an if without an else)

  • Use extractors, if possible, to decompose hierarchies easily in pattern matches.

  • If the code doesn't read well refactor and introduce well named helper functions / methods

梦幻之岛 2024-10-25 06:04:31

第一步可能是这样的,但我确信还有更多的机会(例如,以较小的步骤打破该方法[并由此避免诸如 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
  }

A first step could be something like this, but I'm sure there are more opportunities (e.g. breaking the method in smaller steps [and avoiding things like currentN by this], finding a way to unify loop0 and loop1, which are ugly, replacing the ArrayBuffer by an immutable structure, making visited an 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
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文