2015-12-21 26 views
1

我有一個key -> Map(key1 -> Map(), key2 -> Map())有點類似的嵌套地圖,它基本上代表了一個特定的HTTP請求的路徑結構。在scala中合併兩個嵌套的地圖

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

我已經將它們存儲在一個Map地圖,這將使我的路徑的層次。使用解析器,我從服務器日誌中讀取數據並獲取所需的相應數據,然後將數據編入索引映射中。

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] 
    } 
} 

獲取數據的方法調用每個輸入列表並將其發送到構建地圖的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())))))))

尋找建議我如何能實現此解決方案,並得到一個包含所有存在於服務器日誌文件在一個地圖的可能路徑的最終地圖。

回答

0

也許這樣的事情?

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())) 
+0

該解決方案可能有效,但所需輸出必須稍微有點不同。根據上面的解決方案,輸出將是 'Map(root - > Map(bin - > Map(sh - > Map(),csh - > Map()),usr - > Map()))', 但它應該是 '映射(根 - >映射(bin - >映射(sh - >映射(),csh - >映射(usr - >映射()))))'' – elric

2

合併這兩個地圖可以使用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())))))) 
+0

我將無法使用'| + |方法'當你使用'collection.mutable.HashMap'或甚至'collection.immutable.Map [String,Any]' – elric

+1

地圖需要是相同的類型,你的地圖來自於例子,所以我假設了這一點。我沒有任何地圖的簡單解決方案。順便說一句,嘗試閱讀你發佈的內容,因爲這顯然不是英文。 –

+0

我的地圖屬於同一類型,但scalaz不允許您實現| + |方法在可變映射'collection.mutable.HashMap'上。 這是我得到的錯誤 'error:value | + |不是scala.collection.immutable.Map [String,Any]的成員''。 我要麼必須改變我使用的地圖類型的集合,要麼編寫一些邏輯來完成| + |方法只是爲了一個可變的地圖。 – elric