Arrays 如何在遍历对时克服IndexOutOfBounds异常

Arrays 如何在遍历对时克服IndexOutOfBounds异常,arrays,kotlin,Arrays,Kotlin,假设我有一个a,b,c数组 val arr = arrayOf("a", "b", "c") 我的任务是消除a和b对。 我的做法如下。我遍历数组并检查下一个元素是什么。如果是b,则我将其删除 for (a in arr.indices) { when (arr[a]) { "a" -> { if (arr[a +

假设我有一个
a,b,c
数组

val arr = arrayOf("a", "b", "c")
我的任务是消除
a
b
对。 我的做法如下。我遍历数组并检查下一个元素是什么。如果是
b
,则我将其删除

for (a in arr.indices) {
            when (arr[a]) {
                "a" -> {
                    if (arr[a + 1] == "b"){/replacement part}
当我通过时,这给了我一个IndexOutOfBoundsException

val arr = arrayOf("a") 

这显然是由if条件引起的,我在这里检查
arr[a+1]
,它在我的数组中不存在。我应该用什么方法来克服这个困难?

您应该循环,直到数组长度减2为止。如果您正在寻找配对,那么考虑最后一个元素是没有意义的。因此:

for (a in 0 until a.size - 1) {

    ...
}

通常情况下,有多种方法…  你必须运用你的技能和判断力来决定在你的特殊情况下哪一个是最好的

也许最安全、最普遍的方法是修改测试,首先检查访问该数组元素是否安全:

for (a in arr.indices)
    when (arr[a]) {
        "a" ->
            if (a < arr.length - 1 && arr[a + 1] == "b")
                // …
for (a in 0 .. arr.size - 2)
    when (arr[a]) {
        "a" ->
            if (arr[a + 1] == "b")
                // …
(当然,如果数组类型可为null,并且您正在查找null值,那么这将不起作用。)

另一种方法是在最后一个元素之前停止循环:

for (a in arr.indices)
    when (arr[a]) {
        "a" ->
            if (a < arr.length - 1 && arr[a + 1] == "b")
                // …
for (a in 0 .. arr.size - 2)
    when (arr[a]) {
        "a" ->
            if (arr[a + 1] == "b")
                // …
…尽管这假定循环中没有其他东西需要访问最后一个元素。  如果有人在稍后查看代码时没有发现代码提前停止,则更可能导致错误

(在所有这些情况下,您可以搜索“b”,然后检查前一个字符是否为“a”-但仍然可以得到等价的问题和等价的解决方案。)

另一种方法可能是将字符数组转换为字符串,并使用正则表达式,例如:

val a = arr.joinToString("")
val b = a.replace(Regex("ab"), "cd")

一般来说,使用数组比使用数组更好:它们更通用、更灵活,在标准库中有更多的扩展方法和其他支持,更好地使用泛型,可以是只读的,并且有许多不同的实现可供选择。  Java互操作性、varargs和实现低级数据结构需要阵列;但对于大多数其他用途,列表更可取

例如,如果您有一个列表,您可以找到第一对(如果有)的索引,其中包含:


zipWithNext()
未在数组上定义,因此您不能在您的案例中使用它。)

我不一定推荐它,但是:

@gidds提到了
zipWithNext
对于列表,您可以使用
windowed
执行类似的操作-但它并没有定义为为为2个窗口大小生成漂亮的对,因此您必须处理列表:

val arr = arrayOf("a", "b", "b", "a", "b", "c")

arr.reversed()
    .windowed(size = 2, partialWindows = true)
    .mapNotNull { if (it == listOf("b", "a")) null else it.first() }
    .reversed()
    .toTypedArray() // if you really need an array
    .run(::println)

>> [a, b, a, c]
基本的方法是使用
windowed
遍历数组中的每个项目,抓住它后面的项目-
partialWindows
意味着它将自己抓住最后一个项目,因为后面没有任何内容。这样,您就可以决定是保留还是删除该项(在本例中,通过返回
null
,该项将通过
mapNotNull
从最终列表中筛选出来)

相反的
东西之所以存在,是因为你在看一个项目,以及它后面的内容,并决定是否删除下面的项目——这实际上意味着,当它成为你正在看的主要项目时,记住在下一步删除它。通过反向收集,您可以查看每个项目及其前面的内容,以便决定是否需要删除它。您只需在最后再次反转列表即可


正如您从输出中看到的那样,它正在剥离前面紧靠着
a
的任何
b
,但是在移除
b
之后,您仍然可以得到
a,b
序列。如果您想建立一个列表,并确保在
a
之后没有
b
,您可以使用折叠:

arr.fold(listOf<String>()) { acc, item ->
    if (item == "b" && acc.lastOrNull() == "a") acc else acc + item
}

>> [a, a, c]
arr.fold(listOf()){acc,item->
如果(项目==“b”&&acc.lastOrNull()=“a”)acc else acc+项目
}
>>[a,a,c]
每个步骤要么返回相同的累加器列表,要么创建一个添加了项目的新列表-如果愿意,可以将其设置为可变列表,并在传递该列表之前添加项目(或不添加)


再说一次,我并不是说我一定会推荐你做这些,它更像是工具箱里的一个例子,你知道吗?如果你搞乱了数组,可能是因为你想要xtreme speedz,在这种情况下,你最好迭代索引,然后像其他例子一样回顾。或者,如果要就地删除项并修改阵列本身。看你在干什么

正在删除java标记,因为它是冗余的,很抱歉。