向已有嵌套Map的指定子Map添加键值对失败求解决方案
问题:嵌套Map中指定子Map添加键值对
背景与需求
我有两个Map:
- InputSpec(JSON转换而来的嵌套Map):
Map( id -> Map(prepped -> prepInput), params -> Map( extraParams -> Map( exMap -> Map(obj -> scores, science -> SScoresOD, handler -> hiveHandler), features -> List(a, b, c, d, e, r1, r2, r4, s), category -> AD, exclude -> true, subName -> CD, cxMap -> Map(obj -> scores, science -> SScoresOD, handler -> hiveHandler), Name -> af ), Partition -> 10000000 ) )
- 额外配置Map:
Map("db" -> "targetDB")
需要为InputSpec中的exMap和cxMap添加键值对"db" -> "targetDB",最终得到指定的嵌套结构。
错误尝试
我用递归合并方法尝试实现,但该方法将db键值对添加到了最外层Map,不符合需求:
final def mergeMapsLeftBiased[A <: Any](mapL: Map[A, Any], mapR: Map[A, Any]): Map[A, Any] = { println("mergeMapsLeftBiased") val localSeq = mapR toList val resultMap = if (mapL contains localSeq.head._1) mapL else mapL ++ Map(localSeq.head) if (localSeq.tail isEmpty) resultMap else mergeMapsLeftBiased(resultMap, localSeq.tail.toMap) } val f = mergeMapsLeftBiased(inputDataSpecs, Map("db"-> "targetDB"))
错误输出:
Map[String,Any] = Map( id -> Map(prepped -> prepInput), params -> Map( extraParams -> Map( exMap -> Map(obj -> scores, science -> SScoresOD, handler -> hiveHandler), features -> List(a, b, c, d, e, r1, r2, r4, s), category -> AD, exclude -> true, subName -> CD, cxMap -> Map(obj -> scores, science -> SScoresOD, handler -> hiveHandler), Name -> af ), Partition -> 10000000 ), db -> targetDB )
解决方案
由于是嵌套Map结构,需要逐层定位到目标子Map再修改,以下提供两种实现方式:
方案1:逐层修改(结构固定场景适用)
val dbConfig = Map("db" -> "targetDB") // 逐层提取嵌套Map val params = inputDataSpecs("params").asInstanceOf[Map[String, Any]] val extraParams = params("extraParams").asInstanceOf[Map[String, Any]] // 为目标子Map添加db配置 val updatedExMap = extraParams("exMap").asInstanceOf[Map[String, Any]] ++ dbConfig val updatedCxMap = extraParams("cxMap").asInstanceOf[Map[String, Any]] ++ dbConfig // 重新组装嵌套结构 val updatedExtraParams = extraParams ++ Map( "exMap" -> updatedExMap, "cxMap" -> updatedCxMap ) val updatedParams = params ++ Map("extraParams" -> updatedExtraParams) val finalMap = inputDataSpecs ++ Map("params" -> updatedParams)
方案2:递归通用方法(复杂嵌套场景适用)
如果需要多次修改不同路径的子Map,可使用递归函数定位并更新:
def updateNestedMap( map: Map[String, Any], path: List[String], updateFn: Map[String, Any] => Map[String, Any] ): Map[String, Any] = path match { case Nil => updateFn(map) case key :: rest => map.get(key) match { case Some(subMap: Map[String, @unchecked Any]) => map + (key -> updateNestedMap(subMap, rest, updateFn)) case _ => map // 路径不存在时返回原Map } } val dbConfig = Map("db" -> "targetDB") val updateFn = (m: Map[String, Any]) => m ++ dbConfig // 依次更新exMap和cxMap val tempMap = updateNestedMap(inputDataSpecs, List("params", "extraParams", "exMap"), updateFn) val finalMap = updateNestedMap(tempMap, List("params", "extraParams", "cxMap"), updateFn)
说明
- 方案1代码直观,适合结构固定的场景,调试简单;
- 方案2扩展性强,适合需要频繁修改不同嵌套路径子Map的场景;
- 由于是JSON转换的
Map[String, Any],需用asInstanceOf做类型转换。实际项目中若能定义case class解析JSON,可避免类型转换风险。
内容的提问来源于stack exchange,提问作者Abhishek Priyankar
相关产品推荐
相关产品推荐

