Skip to content

Commit

Permalink
Add more Tree functions
Browse files Browse the repository at this point in the history
  • Loading branch information
lenguyenthanh committed Feb 18, 2024
1 parent 01f5af3 commit 9d1e822
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 4 deletions.
26 changes: 22 additions & 4 deletions src/main/scala/Node.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,15 @@ final case class Node[A](
import Tree.given

final def mainline: List[Node[A]] =
mainlineReverse.reverse

final def mainlineReverse: List[Node[A]] =
@tailrec
def loop(tree: Node[A], acc: List[Node[A]]): List[Node[A]] =
tree.child match
case Some(child) => loop(child, tree :: acc)
case None => tree :: acc
loop(this, Nil).reverse
loop(this, Nil)

// take the first n nodes in the mainline
// keep all variations
Expand All @@ -167,8 +170,20 @@ final case class Node[A](
node.child match
case None => node :: acc
case Some(child) => loop(n - 1, child, node.withoutChild :: acc)
if n == 0 then this
else loop(n, this, Nil).foldLeft(none[Node[A]])((acc, node) => node.withChild(acc).some).getOrElse(this)
if n <= 0 then this
else Tree.buildWithNodeReverse(loop(n, this, Nil)).getOrElse(this)

// take nodes while mainline nodes satisfy the predicate
// keep all variations
def takeMainlineWhile(f: A => Boolean): Option[Node[A]] =
@tailrec
def loop(node: Node[A], acc: List[Node[A]]): List[Node[A]] =
if !f(node.value) then acc
else
node.child match
case None => node :: acc
case Some(child) => loop(child, node.withoutChild :: acc)
Tree.buildWithNodeReverse(loop(this, Nil))

// get the nth node of in the mainline
def apply(n: Int): Option[Node[A]] =
Expand Down Expand Up @@ -475,7 +490,10 @@ object Tree:
build(s.zipWithIndex, f.tupled)

def buildWithNode[A](s: Seq[Node[A]]): Option[Node[A]] =
s.reverse.foldLeft(none)((acc, a) => a.withChild(acc).some)
buildWithNodeReverse(s.reverse)

def buildWithNodeReverse[A](s: Seq[Node[A]]): Option[Node[A]] =
s.foldLeft(none)((acc, a) => a.withChild(acc).some)

def buildWithNode[A, B](s: Seq[A], f: A => Node[B]): Option[Node[B]] =
s.reverse match
Expand Down
8 changes: 8 additions & 0 deletions test-kit/src/test/scala/NodeTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ class NodeTest extends ScalaCheckSuite:
forAll: (node: Node[Int]) =>
node.take(node.mainline.size) == node

test("takeMainlineWhile"):
forAll: (node: Node[Int]) =>
node.takeMainlineWhile(_ % 2 == 0).fold(true)(_.mainlineValues.forall(_ % 2 == 0))

test("takeMainlineWhile == identity when all mainline values satisfy the predicate"):
forAll: (node: Node[Int]) =>
node.takeMainlineWhile(_ => true) == node.some

test("apply(n) return None if n >= node.mainline.size"):
forAll: (node: Node[Int]) =>
node(node.mainline.size).isEmpty
Expand Down

0 comments on commit 9d1e822

Please sign in to comment.