带有案例类的双向参考

发布于 2024-09-19 06:19:19 字数 678 浏览 2 评论 0原文

是否可以在案例类中实现双向树。这看起来应该很容易,但我被难住了,

case class Node(name:String, parent:Option[Node], children:List[Node])

我想添加一个孩子(并获得一个新的根)——类似的东西

def addChild(n:String):Node = {
  Node(name, parent, Node(n, Some(this), Nil)::children)
}

,但这行不通,因为孩子中的“父母”将不再引用将子节点列为子节点的节点。对于不可变列表和案例类,这可能吗?

基于下面给出的答案

case class Node(name: String, parent: () => Option[Node], children: List[Node]) {
  def makeChild(name: String) = {
    lazy val newParent:Node = Node(this.name, this.parent, kid :: this.children)
    lazy val kid:Node = Node(name, () => Some(newParent), Nil)
    newParent
  }
}

Is it possible to implement a bi-directional tree in a case class. This seems like it should be easy, but I'm getting stumped

case class Node(name:String, parent:Option[Node], children:List[Node])

I want to add a child (and get a new root) -- something like

def addChild(n:String):Node = {
  Node(name, parent, Node(n, Some(this), Nil)::children)
}

But that won't work because the "parent" in the child will no longer refer to the Node which lists the child as a child. Is this possible with immutable lists and case classes?

Based on answer given below

case class Node(name: String, parent: () => Option[Node], children: List[Node]) {
  def makeChild(name: String) = {
    lazy val newParent:Node = Node(this.name, this.parent, kid :: this.children)
    lazy val kid:Node = Node(name, () => Some(newParent), Nil)
    newParent
  }
}

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

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

发布评论

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

评论(2

迷迭香的记忆 2024-09-26 06:19:19

我最近在 Twitter 上向 @jamesiry 问了同样的问题:-)。

他的回答是:

sealed abstract class Tree[T]
case class Node[T](left : Tree[T], right : Tree[T]) extends Tree[T]
case class Leaf[T](value : T, parent : () => Tree[T]) extends Tree[T]

def make = {
   lazy val root = Node(left, right)
   lazy val left : Leaf[Int] = Leaf(1, () => root)
   lazy val right : Leaf[Int] = Leaf(2, () => root)
   root
}

I asked the same question to @jamesiry on Twitter recently :-).

His answer:

sealed abstract class Tree[T]
case class Node[T](left : Tree[T], right : Tree[T]) extends Tree[T]
case class Leaf[T](value : T, parent : () => Tree[T]) extends Tree[T]

def make = {
   lazy val root = Node(left, right)
   lazy val left : Leaf[Int] = Leaf(1, () => root)
   lazy val right : Leaf[Int] = Leaf(2, () => root)
   root
}
混浊又暗下来 2024-09-26 06:19:19

请注意:考虑案例类是否是表示树的好选择。

由于案例类是值类型,因此返回父级的唯一方法是返回父级的副本,包括完整子树的副本。然后,如果您枚举其子树,您将再次获得完整子树的副本。

如果您想在树中进行一些替换,例如替换更深层次上的节点,唯一的方法就是复制完整的树并丢弃旧的树。

这一切看起来有点笨拙,但例如 lift- json 使用 case 类来表示 JSON AST,因此这可能不是什么大问题。不确定 Scala 在复制时的参考共享方面有多好。也许有人可以发表评论?

如果您确实想使用案例类,那么上面带有惰性评估的答案是正确的。

Just a note: think if case classes are a good option for you to represent a tree.

Since case classes are value types, the only way to return parent is to return a copy of the parent, including a copy of the full subtree. Then if you for example enumerate its children, you will again get copies of the full subtrees.

If you want to do some replacements in the tree, e.g. replace a node on some deeper level, the only way again is to make a copy of the full tree and throw away the old tree.

This all seems a bit clumsy, but for example lift-json uses case classes to represent JSON ASTs, so it might not be that much of a problem. Not sure how good Scala is at reference sharing when copying. Maybe someone can comment?

If you do want to use case classes, the answer above with lazy evaluation is correct.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文