Best way to iterate IntArray with Index in Kotlin

Viewed 2054

I am looking for a way to best way to iterate IntArray with index similar to below JAVA code

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

I am using below code where I do not want to iterate last element to avoid IndexOutOfBoundException. A.indices allows me to iterate all the indices while I do not want to touch last element just like above:

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
    }
}
3 Answers

One of the functional approaches with immutable variables. Note that Array does not have zipWithNext hence have to convert to Sequence first

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

Edit as per @sschuberth's comment, replaced List with Sequence for better performance.

If you want to iterate the indices as a range, you can use the attribute lastIndex of IntArray in order to avoid an IndexOutOfBoundsException.

Just don't compare an element with its successor, start with the second element and compare its predecessor to it while iterating from index 1 to the last index like this:

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;
}

or like this (thanks for your comment, @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;
}

I have tried it the following way:

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

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

Which gave me the output

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

while an input of intArrayOf(1, 2, 3, 4, 3, 2, 1) resulted in

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

and the input intArrayOf(1, 2, 3, 4, 4, 4, 4) brought up the output

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

In kotlin

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

In this case you can do it like this:

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

Related