【问题标题】:Recursive Types in Scala with a ListScala 中带有列表的递归类型
【发布时间】:2012-10-12 20:41:20
【问题描述】:

类似于mutually recursive types in scala 我正在尝试在 Scala 中创建一个相互递归的类型。

我正在尝试制作一个用这种类型定义的图形(确实可以编译):

 case class Node(val id : Int, val edges : Set[Node])

但我不明白我如何才能用这种类型实际创建一些东西,因为为了用边 B 和 C 初始化节点 A,我至少需要对 B 和 C 进行惰性引用,但我可以' t 同时创建它们的边缘集。

这种递归类型可以实现吗?

编辑:

这是我目前用来将显式邻接列表转换为自引用列表的解决方案。

def mapToGraph(edgeMap : Map[Int, mutable.Set[Int]]) : List[Node] = {
  lazy val nodeMap = edgeMap map  (kv => (kv._1, new Node(kv._1, futures.get(kv._1).get)))
  lazy val futures : Map[Int, Set[Node]] = edgeMap map (kv => {
    val edges = (kv._2 map (e => nodeMap.get(e).get)).toSet
    (kv._1, edges)
  })
  val eval = nodeMap.values.toList
  eval //to force from lazy to real - don't really like doing this
}

或者,来自一个边缘列表

//reads an edgeList into a graph
def readEdgelist(filename : String) : List[Node] = {
  lazy val nodes = new mutable.HashMap[Int, Node]()
  lazy val edges = new mutable.HashMap[Int, mutable.Buffer[Node]]()
  Source.fromFile(filename).getLines() filter (x => x != None) foreach {edgeStr =>
    val edge = edgeStr.split('\t')
    if (edge.size != 2) goodbye("Not a well-formed edge : " + edgeStr + " size: " + edge.size.toString)
    val src = edge(0).toInt
    val des = edge(1).toInt
    if (!(nodes.contains(src))) nodes.put(src, new Node(src, futures.get(src).get))
    if (!(nodes.contains(des))) nodes.put(des, new Node(des, futures.get(des).get))
    edges.put(src, edges.getOrElse(src, mutable.Buffer[Node]()) += nodes.get(des).get)
  }
  lazy val futures : Map[Int, Set[Node]] = nodes map {node => (node._1, edges.getOrElse(node._1, mutable.Buffer[Node]()).toSet)} toMap
  val eval = nodes.values.toList
  eval
}

感谢大家的建议!

【问题讨论】:

标签: scala case-class recursive-datastructures


【解决方案1】:

听起来你需要自下而上地工作

val b = Node(1, Set.empty)
val c = Node(2, Set.empty)
val a = Node(3, Set(b, c))

希望有帮助

【讨论】:

  • 如果边没有方向或图中存在循环,则自下而上无济于事。
  • 进一步,假设您不会制作更大的图表。假设您有一个 List[(Int, Int)] 形式的 edgeList - 您不再持有对每个节点的引用,对吧?
【解决方案2】:

鸡肉和鸡蛋...您有三种选择:

  1. 将您的图限制为有向无环图 (DAG) 并使用 RKumsher 的建议。

  2. 要保持不变性,您需要将节点实例与边集(两个不同的类:创建节点,然后创建边集/图)分开。

  3. 如果您更喜欢紧密相关,请考虑对边集使用设置器,以便在创建所有节点后返回并设置它们。

【讨论】:

  • 基于惰性鸡/蛋引用的解决方案需要显式代码来创建每个鸡/蛋(每个惰性引用);它不适合从文件中批量加载结构松散(即可变的节点数和每个节点的边数)数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-08
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 2021-10-14
  • 1970-01-01
相关资源
最近更新 更多