通过填充或连接最后n个元素将Kotlin列表转换为特定大小

t98cgbkg  于 2023-02-24  发布在  Kotlin
关注(0)|答案(3)|浏览(120)

我经常需要将List缩短或填充到一定数量的条目,为此我使用了如下函数:

fun List<String>.compactOrPadEnd(size: Int): List<String> {
  if (this.size < size)
    return this + List(if (this.size < size) size - this.size else 0) { "" }
  else
    return this.subList(0, size - 1) + this.subList(size - 1, this.size).joinToString("")
}

val list0 = emptyList<String>()
val list1 = listOf("A")
val list2 = listOf("A", "B")
val list3 = listOf("A", "B", "C")
val list4 = listOf("A", "B", "C", "D")
val list5 = listOf("A", "B", "C", "D", "E")

val size = 3
list0. compactOrPadEnd(size).onEach(::println)   // [ ,  , ]
list1. compactOrPadEnd(size).onEach(::println)   // [A,  , ]
list2. compactOrPadEnd(size).onEach(::println)   // [A, B, ]
list3. compactOrPadEnd(size).onEach(::println)   // [A, B, C]
list4. compactOrPadEnd(size).onEach(::println)   // [A, B, CD]
list5. compactOrPadEnd(size).onEach(::println)   // [A, B, CDE]

使用单独的函数时,上述代码的可读性更强:

fun List<String>.padEnd(size: Int) =
    this + List(if (this.size < size) size - this.size else 0) { "" }

fun List<String>.compact(size: Int) = 
    this.subList(0, size - 1) + this.subList(size - 1, this.size).joinToString("")

fun List<String>.compactAndPadEnd(size: Int): List<String> = 
    if (this.size < size) padEnd(size) else compact(size)

我发现这两种解决方案都太笨拙了,我试过所有内置的收集函数,想找到更简单的方法,但没有用。
小编问:还有比 *compactAndPadEnd更好的名字吗 *

dvtswwa3

dvtswwa31#

如果您利用joinToString在列表为空时碰巧返回pad元素""这一事实,则可以将其编写为一个case(即没有if-else)。

fun List<String>.resizeEnd(size: Int): List<String> =
    this.subList(0, min(size - 1, this.size)) +
            this.subList(min(size - 1, this.size), this.size).joinToString("") +
            List(max(0, size - this.size - 1)) { "" }

请注意,我在. -1末尾创建了一个大小为size - this.size - 1的列表,因为其中一个空字符串将是joinToString("")返回的字符串。
如果您不介意droptake创建额外的列表,您可以将其缩短:

fun List<String>.resizeEnd(size: Int): List<String> =
    this.take(size - 1) +
            this.drop(size - 1).joinToString("") +
            List(max(0, size - this.size - 1)) { "" }

您也可以将其概括为:

fun <T> List<T>.resizeEnd(size: Int, padElement: T, foldFunction: (T, T) -> T): List<T> =
    this.subList(0, min(size - 1, this.size)) +
            this.subList(min(size - 1, this.size), this.size).fold(padElement, foldFunction) +
            List(max(0, size - this.size)) { padElement }

但问题是padElement必须是foldFunction的标识。

qyyhg6bp

qyyhg6bp2#

作为一种替代方法,您可以使用初始化器函数结合when来初始化每一项,从而创建固定大小的List:

fun List<String>.resize(size: Int) = List(size) {
    when {
        it == size - 1 && this.size > size -> this.subList(size - 1, this.size).joinToString("")
        this.size > it -> this[it]
        else -> ""
    }
}

我不完全确定这是否不那么笨拙,我想这取决于个人喜好。

y4ekin9u

y4ekin9u3#

我看到你可以对你的函数做一些小的清理,你冗余地检查this.size < size,你可以把return从条件分支中移除,为了简洁你可以使用take/drop

fun List<String>.compactOrPadEnd(size: Int): List<String> {
    return if (this.size < size)
        this + List(size - this.size) { "" }
    else
        take(size - 1) + drop(size - 1).joinToString("")
}

就我个人而言,我称之为concatEndOrPad

相关问题