枚举 swift 字符串时获取 "String.Index"
Getting "String.Index" while enumerating swift string
目前我们迭代字符串如下:
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)
Is there other way to get directly "String.Index" while iterating?
像这样
let greeting = "Hello"
for (stringIndex, char) in greeting.enumeratedXXX() {
let indexAfterCurrentIndex = greeting.index(after: stringIndex)
print(greeting[indexAfterCurrentIndex...])
}
为什么不将 currentIndex 递增 1?
let greeting = "Hello"
for (stringIndex, char) in greeting.enumerated() {
let currentIndex = stringIndex
let nextIndex = currentIndex + 1
print(nextIndex)
}
没有 built-in 功能。您可以将其包装在自定义迭代器中,但随后您只能将相同类型的计算封装在不同的地方,所以这不是答案:)
代码复杂度
但是,您可以提高当前代码的性能:
greeting.index(greeting.startIndex, offsetBy: intIndex)
- 这将为每次循环迭代计算从
startIndex
到结果索引的索引。
- 使用
index(_:offsetBy:)
的索引计算实际上只是另一个循环本身,它 +1
计算每个索引。没有 O(1)
方法可以 "compute" 索引;它是通过 O(n)
中的循环找到的
因此您自己的外循环与 O(n)
线性相关 n
次迭代,每个字符一个。
然后使用内部循环计算索引意味着有 1+2+3+4+5+6+...n = (n^2 + n)/2
次迭代,其中 n
是本例中的 intIndex
。
这意味着该算法的复杂度为 *handwaiving* roundabout 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
}
仍然不是一个简单的 built-in 解决方案,但您也可以包装这个更高效的算法,然后开始!
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...])
}
如果您需要字符串索引,那么您可以枚举 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...])
}
输出:
H - ello
e - llo
l - lo
l - o
o -
一个更简单的变体是
let greeting = "Hello"
for (char, nextIndex) in zip(greeting, greeting.indices.dropFirst()) {
print(char, "-", greeting[nextIndex...])
}
产生 几乎 相同的结果,只是没有最后 character/index 对:
H - ello
e - llo
l - lo
l - o
目前我们迭代字符串如下:
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)
Is there other way to get directly "String.Index" while iterating?
像这样
let greeting = "Hello"
for (stringIndex, char) in greeting.enumeratedXXX() {
let indexAfterCurrentIndex = greeting.index(after: stringIndex)
print(greeting[indexAfterCurrentIndex...])
}
为什么不将 currentIndex 递增 1?
let greeting = "Hello"
for (stringIndex, char) in greeting.enumerated() {
let currentIndex = stringIndex
let nextIndex = currentIndex + 1
print(nextIndex)
}
没有 built-in 功能。您可以将其包装在自定义迭代器中,但随后您只能将相同类型的计算封装在不同的地方,所以这不是答案:)
代码复杂度
但是,您可以提高当前代码的性能:
greeting.index(greeting.startIndex, offsetBy: intIndex)
- 这将为每次循环迭代计算从
startIndex
到结果索引的索引。 - 使用
index(_:offsetBy:)
的索引计算实际上只是另一个循环本身,它+1
计算每个索引。没有O(1)
方法可以 "compute" 索引;它是通过O(n)
中的循环找到的
因此您自己的外循环与 O(n)
线性相关 n
次迭代,每个字符一个。
然后使用内部循环计算索引意味着有 1+2+3+4+5+6+...n = (n^2 + n)/2
次迭代,其中 n
是本例中的 intIndex
。
这意味着该算法的复杂度为 *handwaiving* roundabout 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
}
仍然不是一个简单的 built-in 解决方案,但您也可以包装这个更高效的算法,然后开始!
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...])
}
如果您需要字符串索引,那么您可以枚举 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...])
}
输出:
H - ello e - llo l - lo l - o o -
一个更简单的变体是
let greeting = "Hello"
for (char, nextIndex) in zip(greeting, greeting.indices.dropFirst()) {
print(char, "-", greeting[nextIndex...])
}
产生 几乎 相同的结果,只是没有最后 character/index 对:
H - ello e - llo l - lo l - o