Plage inverse dans Swift
Existe-t-il un moyen de travailler avec des plages inverses dans Swift?
Par exemple:
for i in 5...1 {
// do something
}
Est une boucle infinie.
Je sais que je peux utiliser 1..5
à la place, calculer j = 6 - i
et utiliser j
comme index. Je me demandais s'il y avait quelque chose de plus lisible?
7 réponses
Mise à jour pour la dernière Swift 3 (fonctionne toujours dans Swift 4)
Vous pouvez utiliser la méthode reversed()
sur une plage
for i in (1...5).reversed() { print(i) } // 5 4 3 2 1
Ou stride(from:through:by:)
méthode
for i in stride(from:5,through:1,by:-1) { print(i) } // 5 4 3 2 1
stide(from:to:by:)
est similaire, mais exclut la dernière valeur
for i in stride(from:5,to:0,by:-1) { print(i) } // 5 4 3 2 1
Mise à jour pour la dernière Swift 2
Tout d'abord, les extensions de protocole changent la façon dont reverse
est utilisé:
for i in (1...5).reverse() { print(i) } // 5 4 3 2 1
Stride a été retravaillé dans Xcode 7 Beta 6. La nouvelle utilisation est:
for i in 0.stride(to: -8, by: -2) { print(i) } // 0 -2 -4 -6
for i in 0.stride(through: -8, by: -2) { print(i) } // 0 -2 -4 -6 -8
Cela fonctionne aussi pour Doubles
:
for i in 0.5.stride(to:-0.1, by: -0.1) { print(i) }
Méfiez-vous des comparaisons en virgule flottante ici pour les limites.
Plus Tôt modifier pour Swift 1.2: de Xcode 6 Bêta 4, par et ReverseRange n'existent plus :[
Si vous cherchez simplement à inverser une plage, la fonction reverse est tout ce dont vous avez besoin:
for i in reverse(1...5) { println(i) } // prints 5,4,3,2,1
Comme posté par 0x7fffffffIl y a une nouvelle construction stride qui peut être utilisée pour itérer et incrémenter par des entiers arbitraires. Apple a également déclaré que le support en virgule flottante est à venir.
Provenant de sa réponse:
for x in stride(from: 0, through: -8, by: -2) {
println(x) // 0, -2, -4, -6, -8
}
for x in stride(from: 6, to: -2, by: -4) {
println(x) // 6, 2
}
Il y a quelque chose de troublant dans l'asymétrie de ceci:
for i in (1..<5).reverse()
... par opposition à ceci:
for i in 1..<5 {
Cela signifie que chaque fois que je veux faire une plage inverse, je dois me rappeler de mettre les parenthèses, plus je dois écrire que .reverse()
à la fin, qui sort comme un pouce endolori. C'est vraiment moche par rapport au style C pour les boucles, qui sont symétriques en comptant et en comptant vers le bas. J'ai donc tendance à utiliser le style C pour les boucles à la place. Mais dans Swift 2.2, le style C pour les boucles sont s'en aller! J'ai donc dû me précipiter pour remplacer toutes mes boucles de style C décrémentant avec cette construction laide .reverse()
- me demandant tout le temps, pourquoi diable n'y a-t-il pas un opérateur de plage inverse?
Mais attendez! C'est Swift-nous sommes autorisés à définir nos propres opérateurs!! Nous y voilà:
infix operator >>> {
associativity none
precedence 135
}
func >>> <Pos : ForwardIndexType where Pos : Comparable>(end:Pos, start:Pos)
-> ReverseRandomAccessCollection<(Range<Pos>)> {
return (start..<end).reverse()
}
Alors maintenant, je suis autorisé à dire:
for i in 5>>>1 {print(i)} // 4, 3, 2, 1
Cela couvre juste le cas le plus commun qui se produit dans mon code, mais c'est de loin le cas le plus commun, donc c'est tout ce dont j'ai besoin actuellement.
, j'ai eu une sorte de crise interne à venir avec l'opérateur. J'aurais bien aimé utiliser >..
, comme étant l'inverse de ..<
, mais ce n'est pas juridique: vous ne pouvez pas utiliser un point après un non-point, il semble. J'ai considéré ..>
mais j'ai décidé qu'il était trop difficile de distinguer de ..<
. La bonne chose à propos de >>>
est qu'il vous crie: "down to!"(Bien sûr, vous êtes libre de trouver un autre opérateur. Mais mon conseil est: pour la super symétrie, définissez <<<
pour faire quoi ..<
, et maintenant vous avez <<<
et >>>
, qui sont symétriques et facile à saisir.)
Swift 3 version (Xcode 8 graine 6):
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound) ->
ReversedRandomAccessCollection<CountableRange<Bound>>
where Bound : Comparable, Bound.Stride : Integer {
return (minimum..<maximum).reversed()
}
Version Swift 4 (Xcode 9 beta 3):
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
-> ReversedRandomAccessCollection<CountableRange<Bound>>
where Bound : Comparable & Strideable {
return (minimum..<maximum).reversed()
}
Version Swift 4.2 (Xcode 10 beta 1):
infix operator >>> : RangeFormationPrecedence
func >>><Bound>(maximum: Bound, minimum: Bound)
-> ReversedRandomAccessCollection<Range<Bound>>
where Bound : Strideable {
return (minimum..<maximum).reversed()
}
Il semble que les réponses à cette question ont un peu changé au fur et à mesure que nous avons progressé à travers les bêtas. Depuis la version bêta 4, la fonction by()
et le type ReversedRange
ont été supprimés de la langue. Si vous cherchez à faire une plage inversée, vos options sont maintenant les suivantes:
1: créez une plage avant, puis utilisez la fonction reverse()
pour l'Inverser.
for x in reverse(0 ... 4) {
println(x) // 4, 3, 2, 1, 0
}
for x in reverse(0 ..< 4) {
println(x) // 3, 2, 1, 0
}
2: Utilisez les nouvelles fonctions stride()
ajoutées dans beta 4, qui incluent des fonctions pour spécifier le démarrage et index de fin, ainsi que le montant à parcourir.
for x in stride(from: 0, through: -8, by: -2) {
println(x) // 0, -2, -4, -6, -8
}
for x in stride(from: 6, to: -2, by: -4) {
println(x) // 6, 2
}
Notez que j'ai également inclus le nouvel opérateur de gamme exclusif dans ce post. ..
a été remplacé par ..<
.
Edit: à partir des notes de version de Xcode 6 beta 5 , Apple a ajouté la suggestion suivante pour gérer ceci:
ReverseRange a été supprimé; utilisez lazy (X..
Voici un exemple.
for i in lazy(0...5).reverse() {
// 0, 1, 2, 3, 4, 5
}
Xcode 7, Bêta 2:
for i in (1...5).reverse() {
// do something
}
Swift 3, 4+: vous pouvez le faire comme ceci:
for i in sequence(first: 10, next: {$0 - 1}) {
guard i >= 0 else {
break
}
print(i)
}
Résultat: 10, 9, 8 ... 0
Vous pouvez le personnaliser comme vous le souhaitez. Pour plus d'informations, lisez le func sequence<T>
référence
Cela pourrait être une autre façon de le faire.
(1...5).reversed().forEach { print($0) }
La fonction
Reverse() est utilisée pour le nombre inverse.
Var n: Int / / entrez le numéro
Pour i en 1...Num.inverser() { Print(je) }