【问题标题】:Kotlin error "Index Out Of Bounds Exception"Kotlin 错误“索引超出范围异常”
【发布时间】:2021-07-28 10:06:54
【问题描述】:

我是 Kotlin 的新手,也是编程新手,所以请温柔:)

假设我有一个字符串(它被优化为没有任何重复的字符),我想将该字符串中的所有字符与声明为可变字符列表的字母表进行比较。我想删除字符串中出现的字母表中的任何字符。我的代码如下

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)
        {for (j in alphabet.indices)
             {if (key[i] == alphabet[j])
                  alphabet.removeAt(j)     // 1. this line have error
                  //print(alphabet[j])  //2. but this line runs fine
}}}

在上面的代码中,“alphabet.removeAt(j)”命令有错误,所以我尝试另一个命令打印出字符而不是删除它们,它运行正常。我阅读了一些文章,我知道这个错误与无效索引有关,但我使用了“indices”键,我认为它非常安全。请帮忙

【问题讨论】:

    标签: kotlin mutablelist


    【解决方案1】:

    使用alphabet.indices 进行迭代是安全的,但在修改集合时迭代集合是不安全的。请注意,indices 返回了完整字母表的索引,但随后您从中删除了一些项目,使其更短,因此索引不再有效。

    您无需遍历集合即可找到要删除的项目。你可以这样做:

    alphabet.remove(key[i])
    

    但老实说,你不需要做任何事情。您的问题实际上是两组相减,您可以更轻松地解决它:

    ('a'..'z').toSet() - "keyword".toSet()
    

    【讨论】:

    • 我也打算建议集合,但后来我认为集合破坏了顺序,所以可能不太合适。现在我意识到toSet 实际上创建了一个确实保持迭代顺序的集合。愚蠢的我,我猜。 +1
    • 是的,显然 Kotlin 团队决定默认使用链接集和映射,因此 toSet()toMap()setOf()mapOf() 等函数保持顺序。我想链接集合的开销可以忽略不计,人们通常希望保留顺序,因此将它们设为默认值是有意义的。
    • 哇,太棒了,我还有很多东西需要学习。我已经阅读了一些教程(主要翻译成我的语言),但几乎没有见过这种代码,如此简单但功能强大。谢谢各位
    • @crazydog 重要的是始终首先关注您最终想要实现的什么 - 如果有帮助,请用简单的英语 - 然后再考虑如何 来做。否则你的想法可能会停留在技术细节上,而错过更简单的方法。像 Kotlin 这样的表达性语言为您提供了许多强大的工具,因此您很少需要进行手动迭代等;并且更简单的方法将更容易阅读和理解,并且不太可能出现错误。
    【解决方案2】:

    您可以将整个循环简化为:

    alphabet.retainAll{ it !in key })
    

    alphabet.retainAll { !key.contains(it) }
    

    或者如果您希望过滤后的列表是一个新列表,而不是就地执行:

    val filtered = alphabet.filter { it !in key }
    

    【讨论】:

      【解决方案3】:

      但我使用了“indices”键,我认为它很安全

      嗯,indices 集合仅在进入循环时评估一次,而不是在每次迭代开始时。即使您在内部循环中更改alphabet 的大小,内部循环仍将循环相同的次数,因为它不会再次评估alphabet.indices。它只会在外循环的下一次迭代中再次这样做,但您的代码会在那之前抛出异常。

      除了在删除项目时减少j,您还可以通过以下方式解决此问题

      key.forEach(alphabet::remove)
      

      【讨论】:

      • 我知道问题出在哪里了,谢谢
      • @crazydog 如果您认为某个答案可以回答您的问题,请考虑通过单击该复选标记来接受它!
      猜你喜欢
      • 2011-03-16
      • 1970-01-01
      • 1970-01-01
      • 2015-05-26
      • 2012-06-19
      • 2011-12-25
      相关资源
      最近更新 更多