在 Scala 中转换地图
Transforming a map in Scala
我想在 Scala 中转换 String -> List[String]
类型的映射,以便每个 (k, (List v1, v2, ... vn))
键值对都指向 {(k:v1, k), (k:v2, k), ... (k:vn, k)}
.
对
比如我要改造
scala.collection.immutable.Map[String,List[String]] = Map(A -> List(a1, a2), B -> List(b1))
至
scala.collection.immutable.Map[String,List[String]] = Map(A:a1 -> A, A:a2 -> A, B:b1 -> B)
我能够使用[这个答案][1]部分实现我的目标:
scala> val schema = Map("A" -> List("a1", "a2"), "B" -> List("b1"))
schema: scala.collection.immutable.Map[String,List[String]] = Map(A -> List(a1, a2), B -> List(b1))
scala> schema flatten {case(k, vs) => vs.map((_, k))}
res1: scala.collection.immutable.Iterable[(String, String)] = List((a1,A), (a2,A), (b1,B))
当我尝试为每个值添加原始键和冒号时,出现错误:
scala> schema flatten {case(k, vs) => vs.map((k.concat(":").concat(_), k))}
<console>:13: error: type mismatch;
found : (String => String, String)
required: String => ?
schema flatten {case(k, vs) => vs.map((k.concat(":").concat(_), k))}
- 没有
_
,(k.concat(":").concat(k), k)
里面也没有变量,所以不是函数字面量,但是map
的参数一定是函数。
- 无论如何您都不想将
k
与 k
连接起来
试试这个:
schema.flatMap { case (k, vs) => vs.map(v => (k + ":" + v, k)) }
或更简洁:
for ((k, vs) <- schema; v <- vs) yield (k + ":" + v, k)
编辑
对于每个 k
,表达式 k.concat(":").concat(_)
是一个接受字符串 s
并计算 k + ":" + s
.
的函数
因此,(k.concat(":").concat(_), k)
是
的元组
- 函数
x => k.concat(":").concat(x)
和
- 价值
k
所以它的类型是 (String => String, String)
。这与 String => (String, String)
不同,这仍然不是您想要的。
错误消息告诉您 .map
采用 String => ?
形式的函数,但您向它传递的是 (String, String)
.
的元组
(k.concat(":").concat(k), k)
不是一个函数——而且我认为你并不是想在 concat
.
中放置两次 k
要创建地图,您需要一个带有签名的函数 String => (String, String)
vs.map((k.concat(":").concat(k),k))
错误地将 (String, String)
传递给 map
vs.map((k.concat(":").concat(_),k))
错误地将 (String => String, String)
传递给映射。
vs.map(v => (k.concat(":").concat(v), k))
正确匹配 String => (String, String)
.
然后我们可以得到:
schema flatten {case(k, vs) => vs.map(v => (k.concat(":").concat(v), k)) }
// List((A:a1,A), (A:a2,A), (B:b1,B))
您可以看到这段代码的实际效果 here。
但是,正如 Andrey 的精彩评论所指出的那样,将 flatten
与隐式函数一起使用并不是好的做法。此外,您需要 Map
而不是 List
。由于这两个原因,我认为你应该使用 flatMap
而不是 flatten
:
schema flatMap {case(k, vs) => vs.map(v => (k.concat(":").concat(v), k)) };
// Map(A:a1 -> A, A:a2 -> A, B:b1 -> B)
如果您想尝试一下,请参阅 here。
我想在 Scala 中转换 String -> List[String]
类型的映射,以便每个 (k, (List v1, v2, ... vn))
键值对都指向 {(k:v1, k), (k:v2, k), ... (k:vn, k)}
.
比如我要改造
scala.collection.immutable.Map[String,List[String]] = Map(A -> List(a1, a2), B -> List(b1))
至
scala.collection.immutable.Map[String,List[String]] = Map(A:a1 -> A, A:a2 -> A, B:b1 -> B)
我能够使用[这个答案][1]部分实现我的目标:
scala> val schema = Map("A" -> List("a1", "a2"), "B" -> List("b1"))
schema: scala.collection.immutable.Map[String,List[String]] = Map(A -> List(a1, a2), B -> List(b1))
scala> schema flatten {case(k, vs) => vs.map((_, k))}
res1: scala.collection.immutable.Iterable[(String, String)] = List((a1,A), (a2,A), (b1,B))
当我尝试为每个值添加原始键和冒号时,出现错误:
scala> schema flatten {case(k, vs) => vs.map((k.concat(":").concat(_), k))}
<console>:13: error: type mismatch;
found : (String => String, String)
required: String => ?
schema flatten {case(k, vs) => vs.map((k.concat(":").concat(_), k))}
- 没有
_
,(k.concat(":").concat(k), k)
里面也没有变量,所以不是函数字面量,但是map
的参数一定是函数。 - 无论如何您都不想将
k
与k
连接起来
试试这个:
schema.flatMap { case (k, vs) => vs.map(v => (k + ":" + v, k)) }
或更简洁:
for ((k, vs) <- schema; v <- vs) yield (k + ":" + v, k)
编辑
对于每个 k
,表达式 k.concat(":").concat(_)
是一个接受字符串 s
并计算 k + ":" + s
.
因此,(k.concat(":").concat(_), k)
是
- 函数
x => k.concat(":").concat(x)
和 - 价值
k
所以它的类型是 (String => String, String)
。这与 String => (String, String)
不同,这仍然不是您想要的。
错误消息告诉您 .map
采用 String => ?
形式的函数,但您向它传递的是 (String, String)
.
(k.concat(":").concat(k), k)
不是一个函数——而且我认为你并不是想在 concat
.
k
要创建地图,您需要一个带有签名的函数 String => (String, String)
vs.map((k.concat(":").concat(k),k))
错误地将(String, String)
传递给 mapvs.map((k.concat(":").concat(_),k))
错误地将(String => String, String)
传递给映射。vs.map(v => (k.concat(":").concat(v), k))
正确匹配String => (String, String)
.
然后我们可以得到:
schema flatten {case(k, vs) => vs.map(v => (k.concat(":").concat(v), k)) }
// List((A:a1,A), (A:a2,A), (B:b1,B))
您可以看到这段代码的实际效果 here。
但是,正如 Andrey 的精彩评论所指出的那样,将 flatten
与隐式函数一起使用并不是好的做法。此外,您需要 Map
而不是 List
。由于这两个原因,我认为你应该使用 flatMap
而不是 flatten
:
schema flatMap {case(k, vs) => vs.map(v => (k.concat(":").concat(v), k)) };
// Map(A:a1 -> A, A:a2 -> A, B:b1 -> B)
如果您想尝试一下,请参阅 here。