在 Kotlin 中更改 for 循环的索引

27

我该如何在 Kotlin 中修改循环变量?

对于我的特定情况,我有一个 for 循环,在其中针对某些条件,我想要跳过下一次迭代:

for(i in 0..n) {
  // ...
  if(someCond) {
    i++ // Skip the next iteration
  }
}

但是,当我尝试这样做时,系统告诉我“无法重新分配val变量”。

4个回答

42

你无法改变当前元素,你需要使用 while 循环:

var i = 0
while (i <= n) {
    // do something        
    
    if (someCond) {
        i++ // Skip the next iteration
    }

    i++
}

你在尝试做什么?也许有更习惯用语的方法来实现。

如果你能重构这个逻辑以跳过当前迭代,为什么不使用continue

for (i in 0..n) {
    if (someCond) {
        continue
    }
    // ...
}

顺便提一下:..范围是包含的,所以要遍历例如大小为n的列表,通常需要0..(n - 1),可以更简单地使用until0 until n


在您的具体情况中,您可以使用windowed(Kotlin 1.2):

list.asSequence().filter { someCond }.windowed(2, 1, false).forEach { 
    val (first, second) = it
    // ...
}

asSequence将列表转换为Sequence,消除了filterwindowed创建新List的开销(因为它们现在都返回Sequence)。

如果您希望下一对不包括前一对的最后一个元素,请改用windowed(2, 2, false)


手头的任务涉及遍历相邻的元素对...因此循环使用索引 i 和 i+1 进行操作。当我发现关于 i+1 的某些信息意味着它不应该再被查看时,条件就会发生。 - Kricket
我建议您的 while 循环可以更加简洁,通过将 i 初始化为 -1 并使条件 (++i <= n)。这也可以确保没有分支意外地忘记增加。 - Kricket
@Kricket 我添加了一种方法,可能适合你正在尝试的内容。 - Salem
不完全是这样的。这样做会循环遍历对,如(0,1),(2,3)等,但它永远无法处理(1,2)这一对。 - Kricket
2
我必须说,他们把这件事搞得非常复杂。在我看来,这是 Kotlin 相对于进步而言退步的少数领域之一。 - Beko
@Beko 我想这是个人口味问题,或者至少需要适应一下;我发现自己非常喜欢更加功能化的风格,它绝对有助于防止人为错误。标准库提供了相当多的好用函数,可以很好地匹配概念任务 - 当处理这样的任务时,我更可能会考虑 windowed 或其他 Iterable 内置函数,而不是直接使用索引进行操作。但总是有一些不幸的情况,你最终还是需要某种丑陋的解决方案。 - Salem

1

看起来你真正想做的是在列表上迭代大小为2的滑动窗口。如果你正在使用kotlin 1.2或更高版本,你可以使用List.windowed()库函数。

例如,要考虑每对相邻元素,但丢弃第二个元素为负数的元素,你可以这样做:

val list = listOf(1, 2, 3, -4, -5, 6)
list.windowed(2,1).filter { it[1] > 0 }.apply(::println)

这将打印出什么:

[[1, 2], [2, 3], [-5, 6]]

跳过了配对[3,-4]和[-4,-5]。

-1

虽然很多人用高级的方法或运算符描述问题并提出了解决方案,但我认为这对初学者来说并不合适。我在代码中应用了一个修复程序,以便您可以轻松理解它,并且仅使用 while 循环而不是 for 循环。如果您能够理解并发现其有用,请考虑接受此答案。

fun main(args:Array<String>){

    var alphabet = mutableListOf(
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
    )
    var key = "keyword"
    println(key)
    for (i in key.indices)
    {
        var j = 0
        while (j < alphabet.size) {
            if (key[i] == alphabet[j]){
                alphabet.removeAt(j)     // 1. this line have error
            } else j++
        }
    }
    print(alphabet)
}

最佳答案以一个while循环开始,这个循环比你的更简单、更清晰。 - undefined

-3

请尝试这个方法,

for ((position, item) in list.withIndex()){
}

在这里,您将获得位置和对象。


这根本没有回答实际问题,即如何跳过迭代。 - undefined

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