【问题标题】:Getting "String.Index" while enumerating swift string枚举快速字符串时获取“String.Index”
【发布时间】:2019-11-03 07:46:30
【问题描述】:

目前我们迭代字符串如下:

let greeting = "Hello"
for (intIndex, char) in greeting.enumerated() {
    let currentIndex = greeting.index(greeting.startIndex, offsetBy: intIndex)
    let indexAfterCurrentIndex = greeting.index(after: currentIndex)
    print(greeting[indexAfterCurrentIndex...])
}

我觉得下面写代码是多余的。

let currentIndex = greeting.index(greeting.startIndex, offsetBy: intIndex)

有没有其他方法可以在迭代时直接获取“String.Index”?

类似的东西

let greeting = "Hello"
for (stringIndex, char) in greeting.enumeratedXXX() {
    let indexAfterCurrentIndex = greeting.index(after: stringIndex)
    print(greeting[indexAfterCurrentIndex...])
}

【问题讨论】:

标签: swift string swift-string


【解决方案1】:

没有内置功能。您可以将其包装在自定义迭代器中,但是您只能将相同类型的计算封装在不同的地方,所以这不是答案:)

代码复杂度

但是,您可以提高当前代码的性能:

greeting.index(greeting.startIndex, offsetBy: intIndex)
  • 这将计算从startIndex 到每次循环迭代的结果索引的索引。
  • index(_:offsetBy:) 的索引计算实际上只是另一个循环本身,其中+1s 每个索引。没有“计算”索引的O(1) 方式;它是通过O(n) 中的循环发现的

所以你自己的外部循环与O(n) 是线性的,用于n 迭代,每个字符一个。

然后使用内部循环计算索引意味着有1+2+3+4+5+6+...n = (n^2 + n)/2 迭代,其中n 在这种情况下是intIndex

这意味着该算法具有 *handwaiving* 迂回 O(n + n^2) 的复杂性。二次部分有问题!

更好的方法

您可以将复杂性降低到每次迭代 2 次操作,或O(2n)。只需将先前计算的索引保留在内存中并自己 +1,避免从头开始重新计算。

代码如下:

let greeting = "Hello"
var index = greeting.startIndex
for char in greeting {
    let indexAfterCurrentIndex = greeting.index(after: index)
    print(greeting[indexAfterCurrentIndex...])
    index = indexAfterCurrentIndex
}

仍然不是一个简单的内置解决方案,但您也可以封装这个更高效的算法,然后开始使用!

extension String {
    func forEachCharacterWithIndex(iterator: (String.Index, Character) -> Void) {
        var currIndex = self.startIndex
        for char in self {
            iterator(currIndex, char)
            currIndex = self.index(after: currIndex)
        }
    }
}

let greeting = "Hello"
greeting.forEachCharacterWithIndex { (index, char) in
    let indexAfterCurrentIndex = greeting.index(after: index)
    print(greeting[indexAfterCurrentIndex...])
}

【讨论】:

    【解决方案2】:

    如果你需要字符串索引,那么你可以枚举greeting.indices:

    let greeting = "Hello"
    for index in greeting.indices {
        // ...
    }
    

    如果您需要每个字符及其索引,那么您可以并行枚举字符串和索引:

    let greeting = "Hello"
    for (char, currentIndex) in zip(greeting, greeting.indices) {
        let indexAfterCurrentIndex = greeting.index(after: currentIndex)
        print(char, "-", greeting[indexAfterCurrentIndex...])
    }
    

    输出:

    你好 e-llo 我 - 洛 l - o o-

    一个更简单的变体是

    let greeting = "Hello"
    for (char, nextIndex) in zip(greeting, greeting.indices.dropFirst()) {
        print(char, "-", greeting[nextIndex...])
    }
    

    产生几乎相同的结果,只是没有最后一个字符/索引对:

    你好 e-llo 我 - 洛 l - o

    【讨论】:

      【解决方案3】:

      为什么不将 currentIndex 增加 1 ?

      let greeting = "Hello"
      for (stringIndex, char) in greeting.enumerated() {
          let currentIndex = stringIndex
          let nextIndex = currentIndex + 1
          print(nextIndex)
      }
      

      【讨论】:

      • 您不能用+Int 递增String.Index
      • @ctietze enumerated() 不返回索引。它返回元素偏移量(一个 Int)
      • @LeoDabus 对,但是当 OP 想要使用子字符串时,这无济于事(见标题)。 greeting.index(greeting.startIndex, offsetBy: intIndex + 1) 会短 1 行,但问题是一样的
      猜你喜欢
      • 1970-01-01
      • 2018-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-26
      • 2017-08-01
      • 2015-12-10
      • 1970-01-01
      相关资源
      最近更新 更多