String 如何动态更改Kotlin循环中的条件

String 如何动态更改Kotlin循环中的条件,string,loops,for-loop,kotlin,conditional-statements,String,Loops,For Loop,Kotlin,Conditional Statements,我的任务是,如果两个字符串中有相等的字母,则逐个删除其中的字母,并保持在相同的位置。 我这样做,并且总是得到索引越界异常。无法理解如何修复索引并动态制作我的高端板 var newSecret = StringBuilder(secret) var newGuess = StringBuilder(guess) for (i in newSecret.indices){ if (newSecret[i]==newGuess[i]){

我的任务是,如果两个字符串中有相等的字母,则逐个删除其中的字母,并保持在相同的位置。 我这样做,并且总是得到索引越界异常。无法理解如何修复索引并动态制作我的高端板

   var newSecret = StringBuilder(secret)
    var newGuess = StringBuilder(guess)    

 for (i in newSecret.indices){
            if (newSecret[i]==newGuess[i]){
                newSecret.deleteCharAt(i)
                newGuess.deleteCharAt(i)
                rightPosition++
    
            }

迭代时不更改任何类型的集合是有原因的,即使它不是
集合
的一部分,
StringBuilder
显然是一种集合,因为它具有append和deleteAt函数

如果字符串
0123456789
,则0在索引0中,5在索引5中。但是如果我们去掉,比如说3,那么后面的所有东西,现在都有一个不同的索引。我们有
012456789
,如果您计算,您可以看到5将没有索引4,依此类推。这意味着您的过程将不仅删除不应该删除的内容,而且如果它想删除索引9,那么,它将不再存在,因此,索引超出范围

可能还有其他方法可以做到这一点,它们更有效、更容易理解,但我一直试图保持与示例代码相同的想法

val newSecret = StringBuilder(secret)
val newGuess = StringBuilder(guess)

secret.withIndex()
    .filter { guess.length >= it.index + 1 //in case that guess is shorter than secret (if you know that they are the same length, this part of the predicate can be removed
            && it.value == guess[it.index] }
    .map { it.index }
    .reversed() //we want to delete from end to start, to avoid what we discussed above
    .forEach {
        newSecret.deleteCharAt(it)
        newGuess.deleteCharAt(it)
    }
在上述程序中,如果机密和猜测是:

 val secret = "bar1bar2x5"
 val guess = "foo1foo3y5"
那么newSecret和newGuess将是:

newSecret -> barbar2x
newGuess -> foofoo3y

如果您使用IDE调试代码或只打印语句,您将很快意识到索引
i
正在增加,但
newSecret
newGuess
的长度随着每次
deleteCharAt
调用而减少。因此,
newSecret[i]
将为您提供索引出界异常

@gidds在注释中给出了很好的解释:
newSecret.index
在循环之前只计算一次-删除字符时不会重新计算范围,这是异常的原因

for循环可能不适合此用例,您可以尝试while循环。您必须使用两个字符串的长度检查索引,并仅在需要时递增
i

  val newSecret = StringBuilder("abcdef")
  val newGuess = StringBuilder("abddeg")

  var i = 0
  while(i<newSecret.length && i < newGuess.length) {
    if (newSecret[i] == newGuess[i]) {
      newSecret.deleteCharAt(i)
      newGuess.deleteCharAt(i)
    }
    else i++
  }
val newSecret=StringBuilder(“abcdef”)
val newGuess=StringBuilder(“abddeg”)
变量i=0

虽然(我老实说,我认为你从每个字符串的完整副本开始,然后尝试删除内容,并跟踪新状态,这让事情变得更难。如果你可以从头开始构建字符串,丢弃你不需要的内容,这会更简单:

val newSecret = StringBuilder()
val newGuess = StringBuilder()
secret.zip(guess).forEach { (a, b) ->
    if (a != b) {
        newSecret.append(a)
        newGuess.append(b)
    }
}
zip
获取两个iterables并将它们的元素成对提供给您,每个元素一个(就像拉链将两组牙齿连接在一起)。因此,它非常适合于在相同位置比较项目的情况

我认为当你想要一个
字符串
结果时,这是最具可读性的方法,一般情况是

secret.zip(guess).filterNot { (a, b) -> a == b }.unzip()

其中,
zip
ping为您提供一个对列表,而
unzip
将其转换为一对列表。您也可以在此处使用它,但这意味着您必须调用
joinToString(“”)
在每个列表上,然后将
对的每个组件分配给一个变量…我认为上面的
StringBuilder
版本更好,在这种情况下

可能值得明确指出的是,在问题中,
newSecret.index
在循环之前只计算一次-当字符为e已删除,这是异常的原因。