Home > database >  How to write For loop with two index value in Kotlin?
How to write For loop with two index value in Kotlin?

Time:07-29

I have java code like the following:

class Solution {

    public String longestCommonPrefix(String[] strs) {
        // Argument checks
        if (strs == null || strs.length == 0) return "";
        if (strs.length == 1) return strs[0];
        
        StringBuilder sb = new StringBuilder();
        Arrays.sort(strs);
        char[] first = strs[0].toCharArray();
        char[] last = strs[strs.length - 1].toCharArray();
        for (int i = 0, j = 0; i < first.length && j < last.length; i  , j  ) {
            if (first[i] != last[j]) break;
            sb.append(first[i]);
        }
        return sb.toString();
    }
}

My question is how I write for loop like for (int i = 0, j = 0; i < first.length && j < last.length; i , j ) in Kotlin? Thanks!

CodePudding user response:

In your case both indices are the same, so you can use min function to calculate last index:

import kotlin.math.min

fun longestCommonPrefix() {
    ...
    val first: CharArray = ...
    val last: CharArray = ...
    for (i in 0 until min(first.size, last.size)) {
        if (first[i] != last[i]) break
        sb.append(first[i])
    }
}

CodePudding user response:

As Vadik's answer shows, in this particular case the indexes both take the same values, so only one is needed; that leads to a nice simplification of the code, with a neat Kotlin implementation.

However, there isn't always such a neat solution. So it's worth knowing that any old-style for loop (in C or Java) can be easily converted to a while loop:

for (<initialisers>; <condition>; <updates>) {
    // …loop body…
}

becomes:

<initialisers>;
while (<condition>) {
    // …loop body…
    <updates>;
}

That simple transformation can be done for any for loop, however complicated. And since Kotlin has while, the result translates directly into Kotlin.

A few points to be aware of:

  • If the condition is blank, you'd have to substitute true.

  • Any loop variables are now declared outside the loop, so their scope is larger. That brings the possibility of name clashes (if the outer scope already defines variables with those name(s) — e.g. from expanding an earlier loop), and subtle bugs. So you may need to rename them.

  • Having the loop-control code split across three different places can be less concise, and harder to follow. However, that's more of an issue for simple, obvious loops, which are already well catered for in Kotlin — for the more complex ones that'd need this treatment, this may make them clearer.

CodePudding user response:

Another general thing you can do is use zip to pair up two sequences of values - the result will be as long as the shorter sequence (i.e. only complete pairs):

first.indices.zip(last.indices) { (a, b) ->
    // do something with them - you actually get a Pair so you could skip the
    // deconstruction into two variables, and just refer to it.first and it.second
}

which isn't super useful in this case since both values are incrementing from 0, but you can make it more general:

println(first.indices.zip(0 until last.size step 2))

>> [(0, 0), (1, 2), (2, 4), (3, 6), (4, 8), (5, 10)]

So you can define two separate sequences of values, and make a loop that uses a value from each on every iteration, which is similar to what your for loop is doing. And of course it doesn't have to be indices, you could create sequences of the actual elements you want to reference too.

It's not as efficient (creates a List and Iterables under the hood), but for that you'd really need to work directly with indices in a for loop or with a while like gidds is suggesting. (Unless you know for sure something is compiled to an efficient form, e.g. for (i in first.indices) does compile to a basic for loop with no iterator.)


Also this probably goes against the spirit of what you're doing, but if you keep them as Strings, you can do this:

first.commonPrefixWith(last)

Just in case you didn't know ;)

  • Related