Kotlin链接集合功能性能

时间:2017-09-17 15:02:37

标签: intellij-idea kotlin

我是Kotlin的新手,我正在通过使用IDE提供的技巧解决IntelliJ中的简单谜题来学习该语言。我写了这段代码(找到最重复的数字):

fun main(args: Array<String>) {
    val tracer = mutableMapOf<Int,Int>()
    var currentMaxCount = 0

    val numbers = readLine()!!.split(' ').map(String :: toInt)

    for(number in numbers) {
        val currentCountOfNum = incrementAndGetCurrentCountOf(number, tracer)
        currentMaxCount = if(currentCountOfNum > currentMaxCount) currentCountOfNum else currentMaxCount
    }

    println(currentMaxCount)
}

fun incrementAndGetCurrentCountOf(num : Int, tracer: MutableMap<Int,Int>) =
        if(tracer[num] == null) {
            tracer.put(num, 1)
            1
        } else {
            val newCount = tracer[num]!! + 1
            tracer.put(num, newCount)
            newCount
        }

IDE建议使用以下代码:

    var currentMaxCount = 0
    for(number in numbers) {
            val currentCountOfNum = incrementAndGetCurrentCountOf(number, tracer)
            currentMaxCount = if(currentCountOfNum > currentMaxCount) currentCountOfNum else currentMaxCount
        }

改为:

val currentMaxCount = numbers
            .map { incrementAndGetCurrentCountOf(it, tracer) }
            .max()
            ?: 0

我明白发生了什么。但我想知道如果我使用IDE的建议,性能是否会变为O(2n)。我想出的是O(n)。我知道它在理论上没有什么区别,但我想知道Kotlin是否使用任何魔法将运行时间保持在O(n)。 (欢迎任何进一步缩小代码的其他建议)

1 个答案:

答案 0 :(得分:5)

<强> TL; DR

是的,存在性能影响,因为这些实际上是两次单独的迭代。

在此特定上下文中,您可以通过利用专用的maxBy方法避免执行额外的迭代:

numbers.maxBy { incrementAndGetCurrentCountOf(it, tracer) } ?: 0

重要的是要记住,与Java Streams不同,Kotlin Collections不是懒惰的,所有那些花哨的方法都封装了简单的命令式实现。

因此M链接map调用会在乐观情况下产生O(M * N),即使整个处理可能会被短路,因为访问所有元素都是不必要的:

listOf(1, 2, 3)
      .map {
          println(it)
      }.first()

打印:

1
2
3

在这种情况下,记住asSequence方法的存在是非常重要的,该方法会创建一个由给定集合支持的延迟评估序列:

listOf(1, 2, 3).asSequence()
      .map {
          println(it)
      }.first()

打印:

1