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已删除,这是异常的原因。