2013-05-16 254 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)) 
    }