[英]Scala - Map join values to keys?
I have the following map with target node "E": 我具有目标节点“ E”的以下映射:
val map = Map("A" -> "B", "A" -> "C", "C" -> "D", "C" -> "E")
It describe a directed node graph, which looks like: 它描述了一个有向节点图,如下所示:
A / \ B C / \ D E
I need to enter the graph at any point and generate a route to the target node. 我需要在任何时候输入图并生成到目标节点的路由。
Example 1: Enter at A -> Route: A->C->E
Example 2: Enter at D -> Route: D->C->E
Example 3: Enter at B -> Route: B->A->C->E
Does anyone know of a compact algo which could do this as this must have been attempted before. 有谁知道一个紧凑的算法可以做到这一点,因为以前必须尝试过。
Look forward to hearing from you. 期待您的来信。
Cheers, 干杯,
Jez 耶兹
So, here is it: 就是这样:
val map = List("A" -> "B", "A" -> "C", "C" -> "D", "C" -> "E")
def pathOf(tree: Iterable[(String,String)],from: String,to: String, path: List[String] = Nil): List[String] = {
if(from == to) return to::path
tree.filterNot{ case(a,b) => path.contains(a)||path.contains(b) }
.collect{
case (a,b) if a == to => b
case (a,b) if b == to => a
}.map{ x => pathOf(tree,from,x,to::path) }
.find{ _.nonEmpty }
.getOrElse(Nil)
}
Use case: 用例:
scala> pathOf(map,"B","E").mkString("->")
res1: String = B->A->C->E
scala> pathOf(map,"C","E").mkString("->")
res2: String = C->E
As relatively new to Scala, I take this problem as a good exercise for myself and would like to share my solution with all of you. 作为Scala的新手,我认为这个问题对我自己是一个很好的练习,并希望与大家分享我的解决方案。 Any comments are welcomed!
欢迎任何评论!
BTW, the solution given by @Eastsun is a depth-first search which "memorizes" visited nodes in each path, while mine is a breadth-first search where memorization is not required (though you can definitely add this feature to improve efficiency). 顺便说一句,@ Eastsun提供的解决方案是深度优先搜索,它“存储”每个路径中的访问节点,而我的是广度优先搜索,其中不需要存储(尽管您可以添加此功能以提高效率)。 For trees they yield the same answer but for general graphs they can differ.
对于树木,它们给出相同的答案,但是对于一般图形,它们可以不同。
The neighbors of each node can also be cached for optimization. 每个节点的邻居也可以缓存以进行优化。
val graph = Vector(("A","B"), ("A","C"), ("C","D"), ("C","E"))
def adjacent(a: String) = {
graph flatMap {
case (`a`, x) => Some(x)
case (x, `a`) => Some(x)
case _ => None
}
}
def go(from: String, to: String) {
def expand(paths: Vector[Vector[String]]) {
paths.find(_.last==to) match {
case Some(x) => println(x); return
case None => expand(paths flatMap { e =>
adjacent(e.last) map (e :+ _)
})
}
}
expand(Vector(Vector(from)))
}
// tests
go("A","E") // Vector(A, C, E)
go("B","E") // Vector(B, A, C, E)
go("D","E") // Vector(D, C, E)
Version with memorization: change 带记忆的版本:更改
adjacent(e.last) map (e :+ _)
to 至
adjacent(e.last) filterNot (x => paths.flatten contains x) map (e :+ _)
or put this functionality in the adjacent function. 或将此功能放在相邻功能中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.