Actuellement, nous itérons la chaîne comme ci-dessous:

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...])
}

Je pense qu'écrire sous le code est redondant.

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

Existe-t-il un autre moyen d'obtenir directement "String.Index" lors de l'itération?

Quelque chose comme ça

let greeting = "Hello"
for (stringIndex, char) in greeting.enumeratedXXX() {
    let indexAfterCurrentIndex = greeting.index(after: stringIndex)
    print(greeting[indexAfterCurrentIndex...])
}
0
Faisal Ikwal 20 juin 2019 à 16:15

3 réponses

Meilleure réponse

Il n'y a pas de fonctionnalité intégrée pour cela. Vous pouvez envelopper cela dans un itérateur personnalisé, mais vous n'encapsulez alors que le même type de calcul dans un endroit différent, donc ce n'est pas une réponse :)

Complexité du code

Cependant, vous pouvez améliorer les performances de votre code actuel:

greeting.index(greeting.startIndex, offsetBy: intIndex)
  • Cela calculera l'index de startIndex à l'index résultant pour chaque itération de boucle.
  • Le calcul d'index avec index(_:offsetBy:) est en réalité juste une autre boucle en soi, où il +1 est chaque index. Il n'y a aucun moyen O(1) de "calculer" l'index; il est découvert par une boucle dans O(n)

Donc votre propre boucle externe est linéaire avec O(n) pour n itérations, une pour chaque caractère.

Ensuite, calculer l'index avec une boucle interne signifie qu'il y a 1+2+3+4+5+6+...n = (n^2 + n)/2 itérations, où n est le intIndex dans ce cas.

Cela signifie que l'algorithme a une complexité de * handwaiving * roundabout O(n + n^2). La partie quadratique est problématique!

Meilleure approche

Vous pouvez réduire la complexité à 2 opérations par itération, ou O(2n). Gardez simplement l'index précédemment calculé en mémoire et +1 vous-même, en évitant un recalcul à partir de zéro.

Voici le code:

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

Ce n'est toujours pas une solution simple et intégrée, mais vous pouvez tout aussi bien envelopper cet algorithme plus efficace et c'est parti!

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
ctietze 20 juin 2019 à 13:57

Si vous avez besoin des indices de chaîne, vous pouvez énumérer greeting.indices:

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

Si vous avez besoin de chaque caractère avec son index, vous pouvez énumérer la chaîne et les indices en parallèle:

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

Production:

H - ello
e - llo
l - lo
l - o
o -

Une variante plus simple serait

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

Qui produit presque le même résultat, uniquement sans la dernière paire caractère / index:

H - ello
e - llo
l - lo
l - o
1
Martin R 20 juin 2019 à 14:15

Pourquoi ne pas incrémenter le currentIndex de 1?

let greeting = "Hello"
for (stringIndex, char) in greeting.enumerated() {
    let currentIndex = stringIndex
    let nextIndex = currentIndex + 1
    print(nextIndex)
}
-1
SwatGuard 20 juin 2019 à 13:55