将可变hashmap转换为不可变hashmap

时间:2013-05-16 12:12:57

标签: scala

我正在计算列表中的网址数量。 为了实现这一点,我将添加到一个地图,其中键是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)
          }       
    }

我从一个不可变的地图开始,但发现每次都需要重新分配地图,以便用相关的键维护计数器值。是否存在使用不可变映射完成上述相同任务的解决方案?

4 个答案:

答案 0 :(得分: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]。地图的结构通常与(键,值)元组相同 - 因此在地图中,您可以相应地访问键和值。

答案 1 :(得分: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

答案 2 :(得分:0)

仅使用不可变地图:

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

答案 3 :(得分:0)

创建另一个可变的地图。并附加其他地图以获得新的可变地图。 例如

pageToken