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...

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.
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
}
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
-
@ matt a une solution intéressante où il définit son propre opérateur inverse et l'appelle
>>>. Il ne faut pas beaucoup de code pour définir et est utilisé comme ceci:for index in 5>>>0 { print(index) } // 4 // 3 // 2 // 1 // 0 Consultez sur C-Style Pour Les boucles supprimées de Swift 3
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
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
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
firstet des applications paresseuses répétées denext.
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
*/
Dans Swift 4 et dernier
let count = 50//For example
for i in (1...count).reversed() {
print(i)
}
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
}
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.
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
var sum1 = 0
for i in 0...100{
sum1 += i
}
print (sum1)
for i in (10...100).reverse(){
sum1 /= i
}
print(sum1)
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
}
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.