kotlin中转换/附加到列表的惯用方法?

kotlin中转换/附加到列表的惯用方法?,kotlin,Kotlin,假设我正在尝试实现一些功能: private fun List<Int>.padWithIndices(newLength: Int): List<Int> private fun List.padwithindex(newLength:Int):List 它获取一个列表并返回一个列表,其中包含一些附加值,其中对于每个新值,[i]=i Kotlin为我们提供了许多很好的方法来附加到列表,连接两个不同的列表,创建可变列表等等。这些方法太多了,以至于我不知道在这种情况下哪

假设我正在尝试实现一些功能:

private fun List<Int>.padWithIndices(newLength: Int): List<Int>
private fun List.padwithindex(newLength:Int):List
它获取一个列表并返回一个列表,其中包含一些附加值,其中对于每个新值,[i]=i

Kotlin为我们提供了许多很好的方法来附加到列表,连接两个不同的列表,创建可变列表等等。这些方法太多了,以至于我不知道在这种情况下哪种方法最好,我也不知道是否存在任何隐藏的陷阱。这是我最初的基于循环的解决方案,是否有更高效/惯用的解决方案

fun List<Int>.padWithIndices(newLength: Int): List<Int> {
    var newList = this
    for (x in size until newLength) {
        newList += x
    }
    return newList
}
fun List.padwithindex(newLength:Int):List{
var newList=this
用于(新长度前的x尺寸){
newList+=x
}
返回新列表
}

虽然您的解决方案可读性很强,但它会在
for
-循环的每次迭代中复制原始
列表的所有项,因为
+=
上的
var newList:List
每次都会创建一个新列表。最坏情况下的计算复杂度为O(n²),可以将其提高到O(n)


对于这种特殊情况,当您只想将连续范围附加到列表中时,类似这样的单行函数将起作用:

fun List<Int>.padWithIndices(newLength: Int): List<Int> = 
    plus(size until newLength)

函数返回指定索引处的项,如果索引超出范围,则返回
null
。后者由
?:index
处理


或者,重写您的解决方案,并在函数实现中使用可变列表,将项目附加到其中,然后以只读
列表的形式返回:

fun List.padwithindex(newLength:Int):List=
toMutableList().apply{
addAll(直到newLength的大小)
}

虽然您的解决方案可读性很强,但它会在
for
-循环的每次迭代中复制原始
列表的所有项,因为
+=
上的
var newList:List
每次都会创建一个新列表。最坏情况下的计算复杂度为O(n²),可以将其提高到O(n)


对于这种特殊情况,当您只想将连续范围附加到列表中时,类似这样的单行函数将起作用:

fun List<Int>.padWithIndices(newLength: Int): List<Int> = 
    plus(size until newLength)

函数返回指定索引处的项,如果索引超出范围,则返回
null
。后者由
?:index
处理


或者,重写您的解决方案,并在函数实现中使用可变列表,将项目附加到其中,然后以只读
列表的形式返回:

fun List.padwithindex(newLength:Int):List=
toMutableList().apply{
addAll(直到newLength的大小)
}

这是可行的,但您正在将其添加到循环的列表中,因此可能会触发列表中的重新分配

当列表首先以正确的大小初始化时,效率更高:

fun List<Int>.padWithIndices(newLength: Int): List<Int> = List(newLength) { index ->
    if (index < size) {
        get(index)
    } else {
        index
    }
}
fun List.padwithindex(newLength:Int):List=List(newLength){index->
如果(索引<大小){
获取(索引)
}否则{
指数
}
}

这是可行的,但您正在将其添加到循环的列表中,因此可能会触发列表中的重新分配

当列表首先以正确的大小初始化时,效率更高:

fun List<Int>.padWithIndices(newLength: Int): List<Int> = List(newLength) { index ->
    if (index < size) {
        get(index)
    } else {
        index
    }
}
fun List.padwithindex(newLength:Int):List=List(newLength){index->
如果(索引<大小){
获取(索引)
}否则{
指数
}
}
一个衬里:

fun List<Int>.padWithIndices(newLength: Int): List<Int> =
  toMutableList().apply { addAll(size until newLength) }
fun List.padwithindex(newLength:Int):List=
toMutableList().apply{addAll(大小直到newLength)}
将初始列表转换为
MutableList
(由JVM中的ArrayList支持),然后从复制列表的大小创建
IntRange
,直到
newLength
,调用
MutableList.addAll(Iterable)
,最后向下转换为
list

一行:

fun List<Int>.padWithIndices(newLength: Int): List<Int> =
  toMutableList().apply { addAll(size until newLength) }
fun List.padwithindex(newLength:Int):List=
toMutableList().apply{addAll(大小直到newLength)}

将初始列表转换为
MutableList
(由JVM中的ArrayList支持),然后从复制列表的大小创建
IntRange
,直到
newLength
,调用
MutableList.addAll(Iterable)
最后,我的个人建议是,惰性方法将是最虚构的编程风格,据我的理解,这被认为是kotlin惯用的编程风格,新列表是旧列表的惰性包装,只有在实际需要时才访问原始列表元素。就像java流一样。这假定原始列表是不可变的。我现在无法编写代码,所以这不是一个完整的答案,更多的是一个建议。我个人的建议是,惰性方法将是最虚构的编程风格,据我的理解,它被认为是kotlin惯用的编程风格,其中新列表是旧列表的惰性包装,只有在实际需要时才访问原始列表元素。就像java流一样。这假定原始列表是不可变的。我现在无法编写代码,因此这不是一个完整的答案,更像是一个建议。我将添加使用
plus
作为运算符。我将添加使用
plus
作为运算符。