2013-05-16 521 views
1

我正在統計列表中的網址數量。 爲了實現這一點,我添加到一個地圖,其中的關鍵是URL和值是當前的計數器。每次遇到相同的密鑰,我都會增加計數器。下面是代碼:將可變哈希映射轉換爲不可變哈希映射

var m = new HashMap[String, Int] 
    for(l <- MyList){ 
     val url = l.getUrl() 
      var currentCount : Option[Int] = m.get(url) 
      currentCount match { 
       case Some(value) => 
        var currentCount = value + 1 
        m = m ++ Map(url -> currentCount) 
       case None => 
        m = m ++ Map(url -> 1) 
      }  
    } 

我開始用一個不變的地圖,發現我每次需要時重新分配映射,以與相關聯的密鑰保持計數器值。有沒有解決方案使用不可變的地圖完成上述相同的任務?

回答

3

你可以這樣做:

MyList.groupBy(_.getUrl).map(i => (i._1, i._2.size)) 

這應該給你我不變的Map,由getUrl其中包含的時間getUrl發現數進行分組。

或者,用類型簽名爲清楚:

val grouped Map[String, List[MyList]] = MyList.groupBy(_.getUrl) 
grouped.map(i => (i._1, i._2.size) 

正在發生的事情是,groupBy意志組列表成圖,其關鍵是getUrl,其值是一個List[MyList]其中每個項目的getUrl等於鑰匙。

下一行將通過返回鍵和列表的大小將Map[String, List[MyList]]轉換爲Map[String, Int]。地圖的結構通常與(鍵,值)元組相同 - 因此在地圖中,可以相應地訪問鍵和值。

+0

可你expla在這個函數中發生了什麼:'(i =>(i._1,i._2.size))'? –

+0

我用更多的解釋更新了答案 – jcern

+1

你也可以使用'mapValues'。 –

1

您選擇的可變Map方法非常適合給定的任務,並且應該超過已用空間和時間中的大多數不可變實現。 你應該堅持下去。

這將是很好的風格,以保持可變性地方:

def calculateMap(myList : List[ URL? ]) : immutable.Map[String,Int] = { 
    var m = new scala.collection.mutable.HashMap[String, Int] 
    for{ 
    l <- myList 
    url = l.getUrl() 
    }{ 
     val currentCount = m.get(url) getOrElse 0 
     m += (url -> currentCount + 1) 
    } 
    Map() ++ m // this transforms m in an immutable map 
} 

另外,如果你想提高速度,並使用getURL()方法會阻止,你可以嘗試計算並行的結果,並將其轉換爲地圖是這樣的:

def calculateMapPar(myList : IndexedSeq[ URL? ]) : Map[String,Int] = 
    myList.par.map(url => url.getUrl).groupBy(x => x).mapValues(_.size).seq 
0

只使用不可變的映射:

MyList.foldLeft(Map() : Map[String, Int]) { (map, elem) => 
     val key = elem.getUrl 
     map + (key -> (map.getOrElse(key, 0) + 1)) 
    }