将可变集合转换为不可变集合会引入性能损失

Eya*_*oth 0 collections performance scala

我遇到了一个关于将可变集合转换为不可变集合的奇怪行为,这可能会显着影响性能.

我们来看看下面的代码:

val map: Map[String, Set[Int]] = createMap()
while (true) {
    map.get("existing-key")
}
Run Code Online (Sandbox Code Playgroud)

它只创建一次映射,然后重复访问其中一个enries,其中包含一个值作为值.它可以通过以下几种方式创建地图:

使用不可变集合:

def createMap() = keys.map(key => key -> (1 to amount).toSet).toMap
Run Code Online (Sandbox Code Playgroud)

或者使用可变集合(请注意最后的两个转换选项):

def createMap() = {
    val map = mutable.Map[String, mutable.Set[Int]]()
    for (key <- keys) {
        val set = map.getOrElseUpdate(key, mutable.Set())
        for (i <- 1 to amount) {
            set.add(i)
        }
    }
    map.toMap.mapValues(_.toSet) // option #1
    map.mapValues(_.toSet).toMap // option #2
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,可变#1代码创建了一个映射,toSet无论何时get调用(如果条目存在),它都会调用其值,这可能会导致显着的性能损失(取决于用例).

为什么会这样?如何避免这种情况?

Jea*_*art 5

mapValues只需返回一个地图视图,该视图将此地图的每个键映射到f(this(key)).生成的地图包装原始地图而不复制任何元素.

查看实现,mapValues返回一个MappedValues覆盖该get函数的实例:

def get(key: K) = self.get(key).map(f)
Run Code Online (Sandbox Code Playgroud)

如果要强制实现地图,请toMap在通话后mapValues拨打电话.就像你在#2中所做的那样!