旋转 Kotlin 数组

17
假设我有一个像 1 2 3 4 5 这样的数组,我想将它向左旋转 n 个位置并得到一个新数组。
例如,以上数组的第二次旋转会得到 3 4 5 1 2。我没有找到任何可执行此操作的扩展函数。
5个回答

24

您可以使用内置的java Collections.rotate方法,但您需要将数组首先转换为列表:

val arr = intArrayOf(1, 2, 3, 4, 5)
val list = arr.toList()
Collections.rotate(list, -2)
println(list.toIntArray().joinToString())

输出

3, 4, 5, 1, 2

8

我理解 "get a new one" 的意思是扩展函数应该返回一个新的数组实例,就像这样(省略边界检查,sliceArray 是一个标准库函数):

fun <T> Array<T>.rotate(n: Int) = 
    let { sliceArray(n until size) + sliceArray(0 until n) }

例子

arrayOf(1, 2, 3, 4, 5).rotate(1)
    .also { println(it.joinToString()) } // 2, 3, 4, 5, 1

6

通过将数组切成两部分leftright,然后重新组装成right + left的另一个扩展函数:

fun <T> Array<T>.leftShift(d: Int) {
    val n = d % this.size  // just in case
    if (n == 0) return  // no need to shift

    val left = this.copyOfRange(0, n)
    val right = this.copyOfRange(n, this.size)
    System.arraycopy(right, 0, this, 0, right.size)
    System.arraycopy(left, 0, this, right.size, left.size)
}

所以这样:
val a = arrayOf(1, 2, 3, 4, 5, 6, 7)
a.leftShift(2)
a.forEach { print(" " + it) }

将打印

3 4 5 6 7 1 2

5

简单解决方案:

fun <T> Array<T>.rotateLeft(n: Int) = drop(n) + take(n)
fun <T> Array<T>.rotateRight(n: Int) = takeLast(n) + dropLast(n)

限制条件是 n 必须小于等于数组的长度。

另一种方法是使用以下形式的 Collections.rotate(...)

import java.util.Collections

fun <T> Array<T>.rotate(distance: Int) =
    toList().also { // toList() is a deep copy to avoid changing the original array.
        Collections.rotate(it, distance)
    }

fun main() {
    val xs = arrayOf(1, 2, 3, 4, 5)
    val ys = xs.rotate(-2)
    xs.forEach { print("$it ") } // 1 2 3 4 5
    println(ys) // [3, 4, 5, 1, 2]
}

1
记录一下,您可以使用常规的 Array 构造函数 来构建一个新数组:
inline fun <reified T> Array<T>.rotate(n: Int) = Array(size) { this[(it + n) % size] }

在执行旋转操作时,源数组中索引为it的元素会被复制到目标数组的新位置(it + n) % size

与分块拷贝相比,这种方法稍微慢一些。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接