在Scala中转换地图

时间:2018-05-30 01:27:56

标签: scala anonymous-function scala-collections

我想在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))}

2 个答案:

答案 0 :(得分:1)

  1. _中没有(k.concat(":").concat(k), k)且没有变量,因此它不是函数文字,但map的参数必须是函数。
  2. 您不想将kk联系起来
  3. 试试这个:

    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)

    的元组
    1. 功能x => k.concat(":").concat(x)
    2. k
    3. 因此它的类型为(String => String, String)。这与String => (String, String)不同,而且仍然不是您想要的。

答案 1 :(得分:1)

错误消息告诉您.map采用String => ?形式的函数,但您传递的是(String, String)元组。

(k.concat(":").concat(k), k)不是函数 - 我认为您并不是要将k两次放在concat中。

要创建地图,您需要一个带有签名String => (String, String)

的函数
  • vs.map((k.concat(":").concat(k),k))错误地将(String, String)传递给地图
  • 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中看到此代码。

然而,正如安德烈的优秀评论所指出的,将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