我如何改进 Scala 中的这种广度优先搜索,使其更符合 FP 的习惯?
How can I improve this breadth-first search in Scala to make it more idomatic FP?
一直在寻找一种无需队列即可执行此操作并使其成为尾递归的方法。我在想 LazyLists 也可能有帮助。排队会更快吗?我基本上是通过与下一级子级的每个函数调用向下发送突变状态。
case class Tree [A] (
value : A,
Right: Option[Tree[A]],
Left: Option[Tree[A]]
)
object Tree {
def liftChildren[A](t: Tree[A]) = {
List(t.Left, t.Right).flatten
}
def findChild[A](value: A, t: Tree[A]) : Option[Tree[A]] = {
var lvl = 0
def searchChildren(t: List[Tree[A]]): (Option[Tree[A]], List[Tree[A]]) = {
// could be removed, just for fun
lvl += 1
t.foreach(tt => println(s"Scanning Level ${lvl.toString} Value ${tt.value.toString}"))
//
val curfind = t.find(tt => {
tt.value == value
})
curfind match {
case Some(tr) => (Some(tr), t)
case None => {
val children: List[Tree[A]] = t.flatMap(tt => Tree.liftChildren(tt))
children.isEmpty match {
case true => (None, List.empty)
case false => searchChildren(children)
}
}
}
}
searchChildren(List(t))._1
}
}
object main extends App {
println("hello world")
val tree = Tree[Int](
1,
Some(
Tree[Int](2, None, Some(
Tree[Int](5,None, Some(Tree[Int](6, None,None))))
)
) ,
Some(
Tree[Int](
3,
Some(
Tree[Int](4, None, Some(Tree[Int](7, None,None)))
), None
)
)
)
val res = Tree.findChild(6, tree)
println("FoundIt" + res)
}
一切如我所愿。我只是想知道这是否会更好或更惯用的 FP。猫图书馆有帮助吗?
这是一个尾递归实现,使用模式匹配。
final case class Tree[+A](value: A, left: Option[Tree[A]], right: Option[Tree[A]])
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] = {
import scala.collection.immutable.Queue
@annotation.tailrec
def bfs(queue: Queue[Tree[A]]): Option[Tree[A]] =
queue.dequeueOption match {
case None => None
case Some((tree, remaining)) => tree match {
case Tree(`value`, _, _) => Some(tree)
case Tree(_, Some(left), Some(right)) => bfs(queue = remaining.enqueue(left).enqueue(right))
case Tree(_, Some(left), None) => bfs(queue = remaining.enqueue(left))
case Tree(_, None, Some(right)) => bfs(queue = remaining.enqueue(right))
case Tree(_, None, None) => bfs(queue = remaining)
}
}
bfs(queue = Queue(tree))
}
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] = {
@annotation.tailrec
def dfs(stack: List[Tree[A]]): Option[Tree[A]] =
stack match {
case Nil => None
case tree :: remaining => tree match {
case Tree(`value`, _, _) => Some(tree)
case Tree(_, Some(left), Some(right)) => dfs(stack = left :: right :: remaining)
case Tree(_, Some(left), None) => dfs(stack = left :: remaining)
case Tree(_, None, Some(right)) => dfs(stack = right :: remaining)
case Tree(_, None, None) => dfs(stack = remaining)
}
}
dfs(stack = List(tree))
}
这里有一些使用 LazyList.
的实现
final case class Tree[+A](value: A, children: List[Tree[A]])
// DFS by right.
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] =
LazyList.unfold(List(tree)) {
case Nil => None
case tree :: remaining => Some((tree, tree.children reverse_::: remaining))
}.find(tree => tree.value == value)
// DFS by left.
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] =
LazyList.unfold(List(tree)) {
case Nil => None
case tree :: remaining => Some((tree, tree.children ::: remaining))
}.find(tree => tree.value == value)
// BFS
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] =
LazyList.unfold(Queue(tree)) { queue =>
queue.dequeueOption.map {
case (tree, remaining) => (tree, remaining.enqueueAll(tree.children))
}
}.find(tree => tree.value == value)
一直在寻找一种无需队列即可执行此操作并使其成为尾递归的方法。我在想 LazyLists 也可能有帮助。排队会更快吗?我基本上是通过与下一级子级的每个函数调用向下发送突变状态。
case class Tree [A] (
value : A,
Right: Option[Tree[A]],
Left: Option[Tree[A]]
)
object Tree {
def liftChildren[A](t: Tree[A]) = {
List(t.Left, t.Right).flatten
}
def findChild[A](value: A, t: Tree[A]) : Option[Tree[A]] = {
var lvl = 0
def searchChildren(t: List[Tree[A]]): (Option[Tree[A]], List[Tree[A]]) = {
// could be removed, just for fun
lvl += 1
t.foreach(tt => println(s"Scanning Level ${lvl.toString} Value ${tt.value.toString}"))
//
val curfind = t.find(tt => {
tt.value == value
})
curfind match {
case Some(tr) => (Some(tr), t)
case None => {
val children: List[Tree[A]] = t.flatMap(tt => Tree.liftChildren(tt))
children.isEmpty match {
case true => (None, List.empty)
case false => searchChildren(children)
}
}
}
}
searchChildren(List(t))._1
}
}
object main extends App {
println("hello world")
val tree = Tree[Int](
1,
Some(
Tree[Int](2, None, Some(
Tree[Int](5,None, Some(Tree[Int](6, None,None))))
)
) ,
Some(
Tree[Int](
3,
Some(
Tree[Int](4, None, Some(Tree[Int](7, None,None)))
), None
)
)
)
val res = Tree.findChild(6, tree)
println("FoundIt" + res)
}
一切如我所愿。我只是想知道这是否会更好或更惯用的 FP。猫图书馆有帮助吗?
这是一个尾递归实现,使用模式匹配。
final case class Tree[+A](value: A, left: Option[Tree[A]], right: Option[Tree[A]])
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] = {
import scala.collection.immutable.Queue
@annotation.tailrec
def bfs(queue: Queue[Tree[A]]): Option[Tree[A]] =
queue.dequeueOption match {
case None => None
case Some((tree, remaining)) => tree match {
case Tree(`value`, _, _) => Some(tree)
case Tree(_, Some(left), Some(right)) => bfs(queue = remaining.enqueue(left).enqueue(right))
case Tree(_, Some(left), None) => bfs(queue = remaining.enqueue(left))
case Tree(_, None, Some(right)) => bfs(queue = remaining.enqueue(right))
case Tree(_, None, None) => bfs(queue = remaining)
}
}
bfs(queue = Queue(tree))
}
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] = {
@annotation.tailrec
def dfs(stack: List[Tree[A]]): Option[Tree[A]] =
stack match {
case Nil => None
case tree :: remaining => tree match {
case Tree(`value`, _, _) => Some(tree)
case Tree(_, Some(left), Some(right)) => dfs(stack = left :: right :: remaining)
case Tree(_, Some(left), None) => dfs(stack = left :: remaining)
case Tree(_, None, Some(right)) => dfs(stack = right :: remaining)
case Tree(_, None, None) => dfs(stack = remaining)
}
}
dfs(stack = List(tree))
}
这里有一些使用 LazyList.
的实现final case class Tree[+A](value: A, children: List[Tree[A]])
// DFS by right.
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] =
LazyList.unfold(List(tree)) {
case Nil => None
case tree :: remaining => Some((tree, tree.children reverse_::: remaining))
}.find(tree => tree.value == value)
// DFS by left.
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] =
LazyList.unfold(List(tree)) {
case Nil => None
case tree :: remaining => Some((tree, tree.children ::: remaining))
}.find(tree => tree.value == value)
// BFS
def find[A](value: A)(tree: Tree[A]): Option[Tree[A]] =
LazyList.unfold(Queue(tree)) { queue =>
queue.dequeueOption.map {
case (tree, remaining) => (tree, remaining.enqueueAll(tree.children))
}
}.find(tree => tree.value == value)