【问题标题】:Merging two nested maps in scala在scala中合并两个嵌套地图
【发布时间】:2016-03-27 10:12:28
【问题描述】:

我有一个带有key -> Map(key1 -> Map(), key2 -> Map()) 表示形式的嵌套映射,它基本上表示发出的特定 HTTP 请求的路径结构。

root/twiki/bin/edit/Main/Double_bounce_sender root/twiki/bin/rdiff/TWiki/NewUserTemplate

我已将它们存储在地图地图中,这将为我提供路径的层次结构。使用解析器,我从服务器日志中读取数据并获取所需的相应数据,然后在排序映射中索引数据。

val mainList: RDD[List[String]] = requesturl flatMap ( r => r.toString split("\\?") map (x => parser(x.split("/").filter(x => !x.contains("=")).toList).valuesIterator.toList))

def parser(list: List[String]): Map[Int, String]= {
val m = list.zipWithIndex.map(_.swap).toMap
val sM = SortedMap(m.toSeq:_*)
sM.+(0 -> "root")
}

在获得所需结构中的数据后,我遍历整个集合以将数据结构化为路径图,如下所示

root - twiki - bin - edit - Main - Double_bounce_sender -rdiff - TWiki - NewUserTemplate - oops - etc - local - getInterface

type innerMap = mutable.HashMap[String, Any]

def getData(input: RDD[List[String]]): mutable.HashMap[String, innerMap] ={
var mainMap = new mutable.HashMap[String, innerMap]
for(x <- input){
  val z: mutable.HashMap[String, innerMap] = storeData(x.toIterator, mainMap ,x(0).toString)
  mainMap = mainMap ++ z
}
mainMap
}

def storeData(list: Iterator[String], map: mutable.HashMap[String, innerMap], root: String): mutable.HashMap[String, innerMap]={
list.hasNext match {
  case true =>
    val v = list.next()
    val y = map contains (root) match {
      case true =>
        println("Adding when exists: "+v)
        val childMap = map.get(v).get match {
          case _:HashMap[String, Any] => asInstanceOf[mutable.HashMap[String, innerMap]]
          case _ => new mutable.HashMap[String, innerMap]
        }
        val x = map + (v -> storeData(list, childMap, v))
        x
      case false =>
        val x = map + (v -> storeData(list, new mutable.HashMap[String, innerMap], v))
        x
    }
    y.asInstanceOf[mutable.HashMap[String, innerMap]]
  case false =>
    new mutable.HashMap[String, innerMap]
    }
}

get data 方法调用每个输入列表并将其发送到构建地图的 storeData 方法。

我被困在两个地方。

  • 递归发送到 storeData 的 MainMap(HashMap[String, innerMap]) 每次都作为一个新的空映射。
  • 第二个问题是我试图找出一种方法来合并 2 个没有定义长度的嵌套地图。比如合并下面的地图。

Map(root -> Map(twiki -> Map(bin -> Map(edit -> Map(Main -> Map(Double -> Map()))))))) Map(root -> Map(twiki -> Map(bin -> Map(rdiff -> Map(TWiki -> Map(NewUser -> Map())))))))

寻找有关如何实施此解决方案并获得最终地图的建议,该地图在一张地图中包含服务器日志文件中存在的所有可能路径。

【问题讨论】:

    标签: scala parsing hashmap


    【解决方案1】:

    要合并这两个地图,您可以使用 scalaz 和 |+| 方法

    @ Map("root" ->
        Map("twiki" ->
          Map("bin" ->
            Map("rdiff" ->
              Map("TWiki" ->
                Map("NewUser" ->
                  Map.empty[String, String]))))))
    res2: Map[String, Map[String, Map[String, Map[String, Map[String, Map[String, Map[String, String]]]]]]] =
      Map("root" ->
        Map("twiki" ->
          Map("bin" ->
            Map("rdiff" ->
              Map("TWiki" ->
                Map("NewUser" -> Map()))))))
    
    @ Map("root" ->
        Map("twiki" ->
          Map("bin" ->
            Map("edit" ->
              Map("Main" ->
                Map("Double" ->  Map.empty[String, String]))))))
    res3: Map[String, Map[String, Map[String, Map[String, Map[String, Map[String, Map[String, String]]]]]]] =
      Map("root" ->
        Map("twiki" ->
          Map("bin" ->
            Map("edit" ->
              Map("Main" ->
                Map("Double" -> Map()))))))
    
    res2 |+| res3
    res4: Map[String, Map[String, Map[String, Map[String, Map[String, Map[String, Map[String, String]]]]]]] =
      Map("root" ->
        Map("twiki" ->
          Map("bin" ->
            Map(
              "edit" ->
                Map("Main" ->
                  Map("Double" -> Map())),
              "rdiff" ->
                Map("TWiki" ->
                  Map("NewUser" -> Map()))))))
    

    【讨论】:

    • 当您使用collection.mutable.HashMap 甚至collection.immutable.Map[String, Any] 时,我将无法使用|+| method
    • 地图需要是相同类型的,你的例子中的地图是我假设的。对于任何地图,我都没有简单的解决方案。顺便说一句,尝试阅读您发布的内容,因为这显然不是英文的。
    • 我的地图属于同一类型,但 scalaz 不允许您实现 |+|可变映射 collection.mutable.HashMap 上的方法。这是我得到error: value |+| is not a member of scala.collection.immutable.Map[String,Any] 的错误。我要么必须将我正在使用的集合更改为 Map 类型,要么编写一些逻辑来完全执行 |+|方法只适用于可变映射。
    • 是的,它不是 Map[String, Any] 的成员,因为它不知道如何将 AnyAny 合并。如果任何嵌套地图具有多种类型的元素,我不知道如何轻松合并它。
    【解决方案2】:

    也许是这样的?

    scala>   type Node = Map[String, Any];
    defined type alias Node
    
    scala>   def merge( me : Node, you : Node ) : Node = {
         |     val keySet = me.keySet ++ you.keySet;
         |     def nodeForKey( parent : Node, key : String ) : Node = parent.getOrElse( key, Map.empty ).asInstanceOf[Node]
         |     keySet.map( key => (key -> merge( nodeForKey( me, key ), nodeForKey( you, key ) ) ) ).toMap
         |   }
    merge: (me: Node, you: Node)Node
    
    scala> val path1 = Map( "root" -> Map("bin" -> Map("sh" -> Map.empty) ) )
    path1: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,scala.collection.immutable.Map[Nothing,Nothing]]]] = Map(root -> Map(bin -> Map(sh -> Map())))
    
    scala> val path2 = Map( "root" -> Map( "bin" -> Map("csh" -> Map.empty), "usr" -> Map.empty ) )
    path2: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,scala.collection.immutable.Map[_ <: String, scala.collection.immutable.Map[Nothing,Nothing]]]] = Map(root -> Map(bin -> Map(csh -> Map()), usr -> Map()))
    
    scala> merge( path1, path2 )
    res8: Node = Map(root -> Map(bin -> Map(sh -> Map(), csh -> Map()), usr -> Map()))
    

    【讨论】:

    • 此解决方案可能有效,但所需的输出看起来会有些不同。根据您上面的解决方案,输出将是Map(root -&gt; Map(bin -&gt; Map(sh -&gt; Map(), csh -&gt; Map()), usr -&gt; Map())),但它应该是Map(root -&gt; Map(bin -&gt; Map(sh -&gt; Map(), csh -&gt; Map(usr -&gt; Map()))))
    猜你喜欢
    • 1970-01-01
    • 2022-11-09
    • 1970-01-01
    • 2012-08-31
    • 2017-09-25
    • 1970-01-01
    • 2017-12-07
    • 2017-08-24
    • 2015-04-18
    相关资源
    最近更新 更多