在Kotlin中将一个列表连接到另一个列表的最有效方法是什么?

pgpifvop  于 2022-12-23  发布在  Kotlin
关注(0)|答案(1)|浏览(206)

我从listOfRandoms中1到1000的整数列表开始。
我想从createDatabase列表中对random进行左连接。
我目前在循环中使用find{}语句来完成这个任务,但是感觉太重了。难道没有更好(更快)的方法来达到同样的结果吗?

伪代码

data class DatabaseRow(
  val refKey: Int,
  val random: Int  
)

fun main() {
    val createDatabase = (1..1000).map { i -> DatabaseRow(i, Random()) }
    
    val listOfRandoms = (1..1000).map { j ->
        val lookup = createDatabase.find { it.refKey == j }
        lookup.random
    }
}
mwngjboj

mwngjboj1#

正如评论中提到的,这个问题似乎混淆了数据库和编程的思想,这是没有帮助的。
并且不完全清楚代码的哪些部分是需要的,哪些部分可以替换, 我假设您已经有了createDatabase列表,但是listOfRandoms还可以改进。
“伪”代码编译良好,但以下情况除外:

  • 你没有给予Random()一个import,但是没有一个可能的返回Int, 我假设应该是kotlin.random.Random.nextInt()
  • 因为lookup是可以为空的,所以不能简单地调用lookup.random;一个快速的解决方法是lookup!!.random,但是使用lookup?.random ?: -1等正确地处理空值情况会更安全 (不过,考虑到上面的假设,这是不相关的)。

我认为一般的解决方案是创建一个Map, 这可以很容易地从createDatabase完成,通过调用associate()

val map = createDatabase.associate{ it.refKey to it.random }

这需要花费的时间与列表的大小大致成比例, 在Map中查找值非常高效(近似恒定时间):

map[someKey]

在这种情况下,这会占用更多的内存,因为键和值都是整数,并且会被装箱(作为单独的对象存储在堆中)。 而且,大多数Map使用哈希表,这会占用一些内存。
由于键是(根据注解)“一个从随机数开始的升序列表,比如18123..19123”,在这个特定的例子中,它可以不用任何装箱而存储在一个IntArray正 如你所说,数组索引从0开始,所以直接使用键将需要一个巨大的数组,并且只使用最后几个单元格--但是如果你知道起始键,你可以每次从数组索引中减去它。
创建这样的数组会稍微复杂一些,例如:

val minKey = createDatabase.minOf{ it.refKey }
val maxKey = createDatabase.maxOf{ it.refKey }
val array = IntArray(maxKey - minKey + 1)
for (row in createDatabase)
    array[row.refKey - minKey] = row.random

然后,您可以使用以下命令访问值:

array[someKey - minKey]

......也是恒定时间。
此方法的一些注意事项:

  • 如果createDatabase为空,则minOf()将抛出NoSuchElementException。
  • 如果它有'holes',省略了该范围内的一些键,那么数组将保持默认值0 --你可以使用替代的IntArray构造函数来改变它,该构造函数也接受一个lambda来给出初始值。)
  • 尝试查找该范围之外的值将给予ArrayIndexOutOfBoundsException。

为了保存一点内存而增加额外的复杂性是否值得,将取决于“数据库”的大小,以及它在内存中的时间;除非您有充分的理由认为内存使用将是一个问题,否则我不会增加这种复杂性。

相关问题