【问题标题】:Best way to iterate IntArray with Index in Kotlin在 Kotlin 中使用索引迭代 IntArray 的最佳方法
【发布时间】:2020-09-04 02:58:21
【问题描述】:

我正在寻找一种迭代 IntArray 的最佳方法,其索引类似于下面的 JAVA 代码

for (int i = 0; i < arr.length - 1; i++)

我正在使用下面的代码,我不想迭代最后一个元素以避免IndexOutOfBoundExceptionA.indices 允许我迭代所有索引,而我不想像上面那样触摸最后一个元素:

class Solution {
    fun isMonotonic(A: IntArray): Boolean {
        var increasing : Boolean = false
        var decreasing : Boolean = false

        for (i in A.indices) {
            if (A[i] <= A[i+1]) increasing = true
            if (A[i] >= A[i+1]) decreasing = true
        }

        return increasing && decreasing
    }
}

【问题讨论】:

  • 我不想迭代最后一个元素以避免 IndexOutOfBoundException 你可以访问最后一个元素。如果您尝试访问索引 = arr.length 的不存在元素,IndexOutOfBoundException 将被抛出。
  • 你应该改用for(i in 0 until A.lastIndex)
  • 最后一行不应该是return !(increasing &amp;&amp; decreasing)以符合单调的定义吗?您也不处理包含 0 或 1 个元素的数组的情况。

标签: kotlin functional-programming


【解决方案1】:

具有不可变变量的函数式方法之一。请注意,数组没有zipWithNext,因此必须先转换为Sequence

fun isMonotonic(A: IntArray): Boolean {
    val list = A.asSequence().zipWithNext()
    return !list.any { it.first < it.second } || !list.any { it.first > it.second }
}

编辑根据@sschuberth 的评论,将 List 替换为 Sequence 以获得更好的性能。

【讨论】:

  • 您可以使用asSequence() 而不是toList() 1. 包装数组而不是创建新集合,以及 2. 只根据需要评估尽可能少的项目。
  • 你回答了这个问题,但是函数的结果不正确,单调意味着所有项目要么完全不增加,要么不减少,正如deHaar的答案所示
  • 感谢您的意见。 @冰泡菜。我使用了与 OP 在问题中相同的逻辑。但现在更新了答案
【解决方案2】:

如果您想将索引迭代为一个范围,您可以使用IntArray 的属性lastIndex 以避免IndexOutOfBoundsException

只是不要将一个元素与其后继元素进行比较,从第二个元素开始,并在从索引 1 迭代到最后一个索引时将其前身与它进行比较,如下所示:

fun isMonotonic(A: IntArray): Boolean {
    var increasing : Boolean = false
    var decreasing : Boolean = false

    // iterate the range from 1 to the last index, starting with the second index
    for (i in 1..A.lastIndex) {
        val predecessor = A[i - 1]
        val successor = A[i]

        if (predecessor < successor) { 
            increasing = true
            println("${predecessor} < ${successor}")
        } else if (predecessor > successor) {
            decreasing = true
            println("${predecessor} > ${successor}")
        } else {
            println("${predecessor} = ${successor}")
        }

        // check if you can exit already (current state is not monotonic)
        if (increasing && decreasing) {
            return false;
        }
    }

    // if no intermediate state was "not monotonic", this must be "monotonic"
    return true;
}

或像这样(感谢您的评论,@AnimeshSahu):

fun isMonotonic(A: IntArray): Boolean {
    var increasing : Boolean = false
    var decreasing : Boolean = false

    // iterate the range from 0 to the second last index
    for (i in 0 until A.lastIndex) {
        val predecessor = A[i]
        val successor = A[i + 1]

        if (predecessor < successor) { 
            increasing = true
            println("${predecessor} < ${successor}")
        } else if (predecessor > successor) {
            decreasing = true
            println("${predecessor} > ${successor}")
        } else {
            println("${predecessor} = ${successor}")
        }

        // check if you can exit already (current state is not monotonic)
        if (increasing && decreasing) {
            return false;
        }
    }

    // if no intermediate state was "not monotonic", this must be "monotonic"
    return true;
}

我已经尝试过以下方式:

fun main() {
    var arr = intArrayOf(1, 2, 3, 4, 5, 6, 7)

    if (isMonotonic(arr)) {
        println("monotonic")
    } else {
        println("not monotonic")
    }
}

这给了我输出

1 < 2
2 < 3
3 < 4
4 < 5
5 < 6
6 < 7
monotonic

intArrayOf(1, 2, 3, 4, 3, 2, 1) 的输入导致

1 < 2
2 < 3
3 < 4
4 > 3
not monotonic

输入 intArrayOf(1, 2, 3, 4, 4, 4, 4) 带来了输出

1 < 2
2 < 3
3 < 4
4 = 4
4 = 4
4 = 4
monotonic

【讨论】:

  • 如果设置了增加而下一个是减少,你不能提前退出吗?反之亦然?
  • @Icepickle 我不这么认为,因为需要检查整个序列的单调性(如果您想要数学上正确的结果)。没有提到这段代码的全部目的,所以我只是尽可能地改编了原始示例。反正可以早点退出……
  • wikipedia page,我发现了这个在微积分中,定义在具有实数值的实数子集上的函数 {\displaystyle f}f 当且仅当它被称为单调的要么完全不增加,要么完全不减少。也就是说,根据图 1,单调增加的函数并不一定要增加,它根本不能减少。 这是否意味着一旦方向改变它就不再是单调的?跨度>
  • @Icepickle 是的,确实如此...我显然错了 ;-) 如果两者都是真实的,然后立即退出,我认为......最后的返回值可能只是true,因为之前会检查false的情况。
  • @Icepickle 你说的太对了,我只需要更新我的答案以包含早期退出策略
【解决方案3】:

在科特林中

for (x in 0 until 10) println(x) // Prints 0 through 9

在这种情况下,您可以这样做:

for(i in 0 until A.lastIndex) {
  if(A[i] <= A[i+1]) increasing = true
  if(A[i] >= A[i+1]) decreasing = true
}

official docs

【讨论】:

  • 0 until A.sizeA.indices 相同,当转到 i+1 时,您将得到 IndexOutOfBound 异常。
猜你喜欢
  • 2021-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-16
  • 2013-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多