Scala-fy 一个 java 函数?
我最近将我的任务从 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,首先您可以摆脱
null
,用Option
替换可能为null
的参数。然后在代码中,您可以更改为
两个 while 循环都可以替换为递归函数。您可以将结果作为递归函数中的不可变累加器参数传递,而不是将结果添加到可变变量中。
如果
Node
有提取器,您可以使用外壳保护来进行中端
测试。没有增加太多,但更惯用。我感觉两个 while 循环都可以包含在一个递归中,但我还没有充分考虑算法来决定这一点。如果是这样,您可能会获得
common
提前回报。顺便说一句,那里有一个错误,因为该范围内可能没有共同的祖先。
Well, first you can get rid of
null
, replacing the parameters that might benull
withOption
. In the code, you then changewith
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 themidrange
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.
要对上面的代码进行 Scala 化,您可以采取一些相当通用的步骤:
减少 if 语句的数量并替换强制转换和
使用模式匹配进行类型测试
消除 while 语句
递归函数/方法或
库方法(例如折叠)
通过传递消除变量
累加器到函数/方法中
调用并分配结果以恢复最终累加
通过使用值来减少分配
由 if 和 try 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
第一步可能是这样的,但我确信还有更多的机会(例如,以较小的步骤打破该方法[并由此避免诸如 currentN 之类的事情],找到一种方法来统一
loop0
和loop1
,它很丑陋,用不可变的结构替换了ArrayBuffer
,使访问成为一个Option
)。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
andloop1
, which are ugly, replacing theArrayBuffer
by an immutable structure, making visited anOption
).