我有一个Map [String,String]类型的条目映射和一个Map [String,Map [String,String]]类型的查找映射。我的目标是在第一张地图中查找第二张地图中的匹配项,一旦有了键匹配项,就必须用第二张字典的查找替换第一张字典中的值。该示例将清除所有问题。
到目前为止,我已经提出了一种算法,但是我得到了Some(e)和Some(t)的一个奇怪答案。
第一个条目映射如下:
val entries = Map("fruit" -> "aaa", "animal" -> "bbb", "person" -> "jjj")
第二张地图如下:
val lookup = Map("fruit" -> Map("ccc" -> "orange", "aaa" -> "apple"),
"animal" -> Map("zzz" -> "dog", "bbb" -> "cat"))
我期望的结果如下(注意:由于没有匹配项,因此未正确包含“人”):
val result = Map("fruit" -> "apple", "animal" -> "cat")
我想出的算法如下:
val res = for{ (k, ev) <- entries
lv <- lookup.get(k).get(ev)} yield (k, lv)
此算法给我以下结果,我不知道为什么:
Map(fruit -> e, animal -> t)
e和t来自哪里?
答案 0 :(得分:5)
将其细分为各个组成部分。
for {
(k,v1) <- entries
submap <- lookup.get(k)
v2 <- submap.get(v1)
} yield (k,v2)
//res0: immutable.Map[String,String] = Map(fruit -> apple, animal -> cat)
不确定错误输出中e
和t
的来源。
好的,我知道了。 lv <- lookup.get(k).get(ev)
分别遍历"apple"
和"cat"
的每个字母,但由于Map
中每个键只能有一个键->值对,因此只有最后一个信被保留。
答案 1 :(得分:1)
这将起作用:
val res = for{
(k, ev) <- entries
l1 <- lookup.get(k)
l2 <- l1.get(ev)
} yield {
(k, lv)
}
问题说明:
lookup.get(k).get(ev) //this returns a String <- reason: not known
x <- "apple" //x is now a List[Char] -> List('a','p','p','l','e')
现在:
map += ("animal" -> 'a')
map += ("animal" -> 'p')
map += ("animal" -> 'p')
map += ("animal" -> 'l')
map += ("animal" -> 'e')
map += ("fruit" -> 'c')
map += ("fruit" -> 'a')
map += ("fruit" -> 't')
将导致:
Map("animal" -> 'e', "fruit", 't')
答案 2 :(得分:1)
yield
的文档说明了为什么会发生这种情况:https://docs.scala-lang.org/tutorials/FAQ/yield.html
示例2中的页面指出:
for(x <- c1; y <- c2; z <- c3) yield {...}
is translated into
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
因此,您的理解力会转换为:
entries.flatMap({case (k, ev) => lookup.get(k).get(ev).map(lv => (k, lv)) })
此处的关键是“ apple”和“ cat”中的每一个都是map
完成的字符串(即,您要遍历这些单词的每个字符)。由于Map
正在用("fruit" -> "a") ... ("fruit" -> "e")
更新,因此只有(fruit -> e)
是显而易见的,最终结果是您看到的:
Map(fruit -> e, animal -> t)
一些获得预期结果的方法:
for{ (k, ev) <- entries ;lv <- lookup.get(k)} yield (k, lv.get(ev).get)
或者完全避免连锁理解,而只使用常规的map
:
entries.map({case (k, v) => (k, lookup.get(k).get(v))})
这两个结果均产生Map(fruit -> apple, animal -> cat)
,但请注意,这些解决方案无法处理get
返回None
(即查找映射缺少该键)的情况
答案 3 :(得分:0)
您也可以尝试以下方法获取输出
val output = entries.map{
case (k,v) =>
k -> lookup.get(k).flatMap(_.get(v)).getOrElse(v)
}
这会将您的输出作为
output: scala.collection.immutable.Map[String,String] = Map(fruit -> apple, animal -> cat)
答案 4 :(得分:0)
内联解决方案:
val res = entries.flatMap(e => lookup.get(e._1).flatMap(_.get(e._2).map(e._1->_)))
输出:
res: scala.collection.immutable.Map[String,String] = Map(fruit -> apple, animal -> cat)