Получение "String.Index" при перечислении быстрой строки
В настоящее время мы повторяем строку, как показано ниже:
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...])
}
3 ответа
Для этого нет встроенной функциональности. Вы можете обернуть это в пользовательский итератор, но тогда вы будете инкапсулировать только те же вычисления в другом месте, так что это не ответ:)
Сложность кода
Тем не менее, вы можете улучшить производительность вашего текущего кода:
greeting.index(greeting.startIndex, offsetBy: intIndex)
- Это рассчитает индекс из
startIndex
в результирующий индекс для каждой итерации цикла. - Расчет индекса с
index(_:offsetBy:)
на самом деле просто еще один цикл, где он+1
каждый индекс. Нет никакихO(1)
способ "вычислить" индекс; это обнаруживается петлей вO(n)
Таким образом, ваш собственный внешний цикл является линейным с O(n)
за n
итерации, по одной на каждого персонажа.
Затем вычисление индекса с помощью внутреннего цикла означает, что есть 1+2+3+4+5+6+...n = (n^2 + n)/2
итерации, где n
это intIndex
в этом случае.
Это означает, что алгоритм имеет сложность * обхода * обходной 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...])
}
Если вам нужны строковые индексы, вы можете перечислить 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...])
}
Выход:
Привет е - лло л - вот л - о о -
Более простой вариант будет
let greeting = "Hello"
for (char, nextIndex) in zip(greeting, greeting.indices.dropFirst()) {
print(char, "-", greeting[nextIndex...])
}
который дает почти тот же результат, только без последней пары символ / индекс:
Привет е - лло л - вот л - о
Почему бы не увеличить currentIndex на 1?
let greeting = "Hello"
for (stringIndex, char) in greeting.enumerated() {
let currentIndex = stringIndex
let nextIndex = currentIndex + 1
print(nextIndex)
}