Получение "String.Index" при перечислении быстрой строки - PullRequest
0 голосов
/ 20 июня 2019

В настоящее время мы выполняем итерацию строки, как показано ниже:

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 ]

2 голосов
/ 20 июня 2019

Для этого нет встроенных функций.Вы можете обернуть это в пользовательский итератор, но тогда вы будете инкапсулировать только те же вычисления в другом месте, так что это не ответ:)

Сложность кода

Однако вы можете улучшитьпроизводительность вашего текущего кода:

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...])
}
1 голос
/ 20 июня 2019

Если вам нужны строковые индексы, вы можете перечислить 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...])
}

, который выдает почти тот же результат, только без последней пары символ / индекс:

H - ello
e - llo
l - lo
l - o
0 голосов
/ 20 июня 2019

Почему бы не увеличить currentIndex на 1?

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