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 Int
s!
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
first
et 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.