Comment itérer pour la boucle dans l'ordre inverse dans swift?

Lorsque j'utilise la boucle for Dans Playground, tout a bien fonctionné, jusqu'à ce que je change le premier paramètre de la boucle for pour qu'il soit la valeur la plus élevée. (itéré par ordre décroissant)

Est-ce un bug? N'importe qui d'autre l'ont?

for index in 510..509
{
    var a = 10
}

Le compteur qui affiche le nombre d'itérations qui seront exécutées continue de cocher...

entrez la description de l'image ici

128
demandé sur Suragch 2014-07-01 14:59:32

13 réponses

Xcode 6 beta 4 a ajouté deux fonctions pour itérer sur des plages avec une étape autre qu'une: stride(from: to: by:), qui est utilisé avec des plages exclusives et stride(from: through: by:), qui est utilisé avec des plages inclusives.

Pour itérer sur une plage dans l'ordre inverse, ils peuvent être utilisés comme ci-dessous:

for index in stride(from: 5, to: 1, by: -1) {
    print(index)
}
//prints 5, 4, 3, 2

for index in stride(from: 5, through: 1, by: -1) {
    print(index)
}
//prints 5, 4, 3, 2, 1

Notez qu'aucune de ces fonctions n'est une fonction membre Range. Ce sont des fonctions globales qui renvoient une structure StrideTo ou StrideThrough, qui sont définies différemment de la structure Range.

Une version précédente de cette la réponse a utilisé la fonction by() membre de la structure Range, qui a été supprimée dans la version bêta 4. Si vous voulez voir comment cela a fonctionné, Vérifiez l'historique d'édition.

156
répondu Cezar 2016-06-16 14:42:05

Appliquer la fonction inverse à la plage pour itérer en arrière:

Pour Swift 1.2 et antérieures:

// Print 10 through 1
for i in reverse(1...10) {
    println(i)
}

Il fonctionne également avec des plages semi-ouvertes:

// Print 9 through 1
for i in reverse(1..<10) {
    println(i)
}

Note: reverse(1...10) crée un tableau de type [Int], donc bien que cela puisse convenir pour les petites plages, il serait sage d'utiliser lazy comme indiqué ci-dessous ou de considérer la réponse acceptée stride si votre plage est grande.


Pour éviter de créer un grand tableau, utiliser lazy avec reverse(). Le test suivant fonctionne efficacement dans un terrain de jeu montrant qu'il ne crée pas un tableau avec un billion de Ints!

Essai:

var count = 0
for i in lazy(1...1_000_000_000_000).reverse() {
    if ++count > 5 {
        break
    }
    println(i)
}

Pour Swift 2.0 dans Xcode 7:

for i in (1...10).reverse() {
    print(i)
}

Notez que dans Swift 2.0, {[13] } est de type ReverseRandomAccessCollection<(Range<Int>)>, donc cela fonctionne bien:

var count = 0
for i in (1...1_000_000_000_000).reverse() {
    count += 1
    if count > 5 {
        break
    }
    print(i)
}

Pour Swift 3.0 reverse() a été renommé reversed():

for i in (1...10).reversed() {
    print(i) // prints 10 through 1
}
186
répondu vacawama 2016-08-14 16:33:03

mise à Jour pour Swift 3

La réponse ci-dessous est un résumé des options disponibles. Choisissez celui qui correspond le mieux à vos besoins.

reversed: nombres dans une plage

En avant

for index in 0..<5 {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

En Arrière

for index in (0..<5).reversed() {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

reversed: éléments dans SequenceType

let animals = ["horse", "cow", "camel", "sheep", "goat"]

En avant

for animal in animals {
    print(animal)
}

// horse
// cow
// camel
// sheep
// goat

En Arrière

for animal in animals.reversed() {
    print(animal)
}

// goat
// sheep
// camel
// cow
// horse

reversed: éléments avec un index

Parfois, un index est nécessaire lorsque itérer à travers une collection. Pour cela, vous pouvez utiliser enumerate(), qui renvoie un tuple. Le premier élément du tuple est l'index et le deuxième élément est l'objet.

let animals = ["horse", "cow", "camel", "sheep", "goat"]

En avant

for (index, animal) in animals.enumerated() {
    print("\(index), \(animal)")
}

// 0, horse
// 1, cow
// 2, camel
// 3, sheep
// 4, goat

En Arrière

for (index, animal) in animals.enumerated().reversed()  {
    print("\(index), \(animal)")
}

// 4, goat
// 3, sheep
// 2, camel
// 1, cow
// 0, horse

Notez que comme Ben Lachman l'a noté dans sa réponse , vous voulez probablement faire .enumerated().reversed() plutôt que .reversed().enumerated() (ce qui ferait augmenter les indices).

Foulée: nombres

La foulée est un moyen d'itérer sans à l'aide d'une fourchette. Il y a deux formes. Les commentaires à la fin du code montrent quelle serait la version de la plage (en supposant que la taille de l'incrément est 1).

startIndex.stride(to: endIndex, by: incrementSize)      // startIndex..<endIndex
startIndex.stride(through: endIndex, by: incrementSize) // startIndex...endIndex

En avant

for index in stride(from: 0, to: 5, by: 1) {
    print(index)
}

// 0
// 1
// 2
// 3
// 4

En Arrière

Changer la taille de l'incrément à -1 Vous permet de revenir en arrière.

for index in stride(from: 4, through: 0, by: -1) {
    print(index)
}

// 4
// 3
// 2
// 1
// 0

Notez la différence to et through.

Stride: éléments de SequenceType

De l'Avant par incréments de 2

let animals = ["horse", "cow", "camel", "sheep", "goat"]

J'utilise 2 dans cet exemple juste pour montrer une autre possibilité.

for index in stride(from: 0, to: 5, by: 2) {
    print("\(index), \(animals[index])")
}

// 0, horse
// 2, camel
// 4, goat

En Arrière

for index in stride(from: 4, through: 0, by: -1) {
    print("\(index), \(animals[index])")
}

// 4, goat
// 3, sheep 
// 2, camel
// 1, cow  
// 0, horse 

Notes

75
répondu Suragch 2018-06-27 23:40:36

Swift 4 à partir de

for i in stride(from: 5, to: 0, by: -1) {
    print(i)
}
//prints 5, 4, 3, 2, 1

for i in stride(from: 5, through: 0, by: -1) {
    print(i)
}
//prints 5, 4, 3, 2, 1, 0
38
répondu Irfan 2017-10-15 05:57:38

Pour Swift 2.0 et supérieur, vous devez appliquer l'inverse sur une collection de plages

for i in (0 ..< 10).reverse() {
  // process
}

Il a été renommé en .inversé() dans Swift 3.0

23
répondu Andrew Luca 2017-01-10 02:44:05

Avec Swift 3, selon vos besoins, vous pouvez choisir l'une des huit implémentations de code Playground suivantes afin de résoudre votre problème.


#1. À l'aide de CountableClosedRange reversed() méthode

CountableClosedRange a une méthode appelée reversed(). reversed() méthode a la déclaration suivante:

func reversed() -> ReversedRandomAccessCollection<CountableClosedRange<Bound>>

Renvoie une vue présentant les éléments de la collection dans l'ordre inverse.

Utilisation:

let reversedRandomAccessCollection = (0 ... 5).reversed()

for index in reversedRandomAccessCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#2. À l'aide de CountableRange reversed() méthode

CountableRange a une méthode appelée reversed(). reversed() méthode a la déclaration suivante:

func reversed() -> ReversedRandomAccessCollection<CountableRange<Bound>>

Renvoie une vue présentant les éléments de la collection dans l'ordre inverse.

Utilisation:

let reversedRandomAccessCollection = (0 ..< 6).reversed()

for index in reversedRandomAccessCollection {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#3. Utilisation de la fonction sequence(first:next:)

Swift de la Bibliothèque Standard fournit une fonction appelée sequence(first:next:). sequence(first:next:) a la déclaration suivante:

func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldSequence<T, (T?, Bool)>

Renvoie une séquence formé à partir de first et des applications paresseuses répétées de next.

Utilisation:

let unfoldSequence = sequence(first: 5, next: {
    $0 > 0 ? $0 - 1 : nil
})

for index in unfoldSequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#4. Utilisation de la fonction stride(from:through:by:)

Swift de la Bibliothèque Standard fournit une fonction appelée stride(from:through:by:). stride(from:through:by:) a la déclaration suivante:

func stride<T>(from start: T, through end: T, by stride: T.Stride) -> StrideThrough<T> where T : Strideable

Renvoie la séquence de valeurs (self, self + stride, self + 2 * stride, … last) où last est la dernière valeur de la progression inférieure ou égale à end.

Utilisation:

let sequence = stride(from: 5, through: 0, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#5. Utiliser stride(from:to:by:) fonction

Swift de la Bibliothèque Standard fournit une fonction appelée stride(from:to:by:). stride(from:to:by:) a la déclaration suivante:

func stride<T>(from start: T, to end: T, by stride: T.Stride) -> StrideTo<T> where T : Strideable

Renvoie la séquence de valeurs (self, self + stride, self + 2 * stride, … last) où last est la dernière valeur de la progression inférieure à end.

Utilisation:

let sequence = stride(from: 5, to: -1, by: -1)

for index in sequence {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#6. À l'aide de AnyIterator init(_:) initialiseur

AnyIterator a un initialiseur appelé init(_:). init(_:) A ce qui suit déclaration:

init<I>(_ base: I) where I : IteratorProtocol, I.Element == Element

Crée un itérateur qui enveloppe un itérateur de base mais dont le type dépend uniquement du type d'élément de l'itérateur de base.

Utilisation:

var index = 5

guard index >= 0 else { fatalError("index must be positive or equal to zero") }

let iterator = AnyIterator<Int>({
    defer { index = index - 1 }
    return index >= 0 ? index : nil
})

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#7. À l'aide de AnyIterator init(_:) initialiseur

AnyIterator a un initialiseur appelé init(_:). init(_:) a la déclaration suivante:

init(_ body: @escaping () -> AnyIterator.Element?)

Crée un itérateur qui enveloppe la fermeture donnée dans son next() méthode.

Utilisation:

var index = 5

guard index >= 0 else { fatalError("index must be positive or equal to zero") }

let iterator = AnyIterator({ () -> Int? in
    defer { index = index - 1 }
    return index >= 0 ? index : nil
})

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/

#8. Utilisation d'une méthode d'extension Int personnalisée

Vous pouvez refactoriser le code précédent en créant une méthode d'extension pour Int et en enveloppant votre itérateur:

extension Int {

    func iterateDownTo(_ endIndex: Int) -> AnyIterator<Int> {
        var index = self
        guard index >= endIndex else { fatalError("self must be greater than or equal to endIndex") }

        let iterator = AnyIterator { () -> Int? in
            defer { index = index - 1 }
            return index >= endIndex ? index : nil
        }
        return iterator
    }

}

let iterator = 5.iterateDownTo(0)

for index in iterator {
    print(index)
}

/*
Prints:
5
4
3
2
1
0
*/
15
répondu Imanou Petit 2018-02-01 13:29:57

Dans Swift 4 et dernier

    let count = 50//For example
    for i in (1...count).reversed() {
        print(i)
    }
7
répondu Rohit Sisodia 2018-03-26 06:21:46

Swift 4.0

for i in stride(from: 5, to: 0, by: -1) {
    print(i) // 5,4,3,2,1
}

Si vous voulez inclure la valeur to:

for i in stride(from: 5, through: 0, by: -1) {
    print(i) // 5,4,3,2,1,0
}
5
répondu William Hu 2017-09-29 09:38:40

Si l'on veut parcourir un tableau (Array ou plus généralement tout SequenceType) à l'envers. Vous avez quelques options supplémentaires.

Vous pouvez d'abord {[2] } le tableau et le parcourir comme d'habitude. Cependant, je préfère utiliser enumerate() la plupart du temps car il génère un tuple contenant l'objet et son index.

La seule chose à noter ici est qu'il est important d'appeler ces dans le bon ordre:

for (index, element) in array.enumerate().reverse()

Donne des indices par ordre décroissant (qui est ce que je m'attends généralement). considérant ce qui suit:

for (index, element) in array.reverse().enumerate() (ce qui est une correspondance plus proche de NSArray reverseEnumerator)

Marche le tableau en arrière mais affiche des index ascendants.

3
répondu Ben Lachman 2016-06-03 16:51:58

Comme pour Swift 2.2 , Xcode 7.3 (10,juin,2016) :

for (index,number) in (0...10).enumerate() {
    print("index \(index) , number \(number)")
}

for (index,number) in (0...10).reverse().enumerate() {
    print("index \(index) , number \(number)")
}

Sortie :

index 0 , number 0
index 1 , number 1
index 2 , number 2
index 3 , number 3
index 4 , number 4
index 5 , number 5
index 6 , number 6
index 7 , number 7
index 8 , number 8
index 9 , number 9
index 10 , number 10


index 0 , number 10
index 1 , number 9
index 2 , number 8
index 3 , number 7
index 4 , number 6
index 5 , number 5
index 6 , number 4
index 7 , number 3
index 8 , number 2
index 9 , number 1
index 10 , number 0
2
répondu PeiweiChen 2016-06-10 03:46:36
var sum1 = 0
for i in 0...100{
    sum1 += i
}
print (sum1)

for i in (10...100).reverse(){
    sum1 /= i
}
print(sum1)
1
répondu Abo3atef 2016-07-21 05:19:19

Vous pouvez envisager d'utiliser la boucle C-Style while à la place. Cela fonctionne très bien dans Swift 3:

var i = 5 
while i > 0 { 
    print(i)
    i -= 1
}
1
répondu Nitin Nain 2017-05-07 13:33:53

Vous pouvez utiliser la méthode reversed() pour inverser facilement les valeurs.

var i:Int
for i in 1..10.reversed() {
    print(i)
}

La méthode reversed() inverse les valeurs.

1
répondu SIDHARTH P U 2018-06-19 06:04:20