Comment puis-je écrire ce qui suit dans Swift3?
for (f = first; f <= last; f += interval)
{
n += 1
}
C'est ma propre tentative
for _ in 0.stride(to: last, by: interval)
{
n += 1
}
Strideable
: s stride(...)
remplacée par une fonction globale stride(...)
Dans Swift 2.2, nous pouvons (comme vous l'avez essayé dans votre propre tentative) utiliser les fonctions blueprinted (et implémentées par défaut) stride(through:by:)
et stride(to:by:)
du protocole Strideable
/* Swift 2.2: stride example usage */ let from = 0 let to = 10 let through = 10 let by = 1 for _ in from.stride(through, by: by) { } // from ... through (steps: 'by') for _ in from.stride(to, by: by) { } // from ..< to (steps: 'by')
Alors que dans Swift 3.0, ces deux fonctions ont été supprimées de Strideable
au profit de les fonctions globales stride(from:through:by:)
et stride(from:to:by:)
; d’où l’équivalent Swift 3.0 de ce qui suit est la suivante:
/* Swift 3.0: stride example usage */ let from = 0 let to = 10 let through = 10 let by = 1 for _ in stride(from: from, through: through, by: by) { } for _ in stride(from: from, to: to, by: by) { }
Dans votre exemple, vous souhaitez utiliser l'alternative de foulée à intervalle fermé stride(from:through:by:)
, car l'invariant de votre boucle for
utilise la comparaison avec less ou égal à (<=
). C'est à dire.
/* example values of your parameters 'first', 'last' and 'interval' */
let first = 0
let last = 10
let interval = 2
var n = 0
for f in stride(from: first, through: last, by: interval) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
Où naturellement nous utilisons votre boucle for
uniquement comme exemple du passage de for
loop à stride
, comme vous pouvez le faire naturellement, par exemple, calculez n
sans avoir besoin d'une boucle (n=1+(last-first)/interval
).
stride
pour une logique d’incrémentation plus complexeAvec mise en œuvre de la proposition d’évolution SE-0094 , Swift 3.0 a introduit les fonctions globales sequence
:
ce qui peut être une alternative appropriée à stride
pour les cas avec une relation d'incrémentation d'itération plus complexe (ce qui n'est pas le cas dans cet exemple).
Déclaration (s)
func sequence<T>(first: T, next: @escaping (T) -> T?) -> UnfoldSequence<T, (T?, Bool)> func sequence<T, State>(state: State, next: @escaping (inout State) -> T?) -> UnfoldSequence<T, State>
Nous allons brièvement examiner la première de ces deux fonctions. Les arguments next
prennent une fermeture qui applique une certaine logique à la construction lente de l'élément suivant de la séquence en fonction de l'élément actuel (commençant par first
). La séquence est terminée lorsque next
renvoie nil
, ou infini, si un next
ne renvoie jamais nil
.
Appliquée à l'exemple simple à pas constant ci-dessus, la méthode sequence
est un peu verbeuse et déborde w.r.t. la solution adaptée à cet usage stride
:
let first = 0
let last = 10
let interval = 2
var n = 0
for f in sequence(first: first,
next: { $0 + interval <= last ? $0 + interval : nil }) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
Les fonctions sequence
deviennent très utiles pour les cas à foulée non constante, cependant, par ex. comme dans l'exemple couvert dans le Q & A suivant:
Veillez simplement à mettre fin à la séquence avec un éventuel retour nil
(sinon: une génération d'éléments "infinie") ou, lorsque Swift 3.1 arrive, utilisez sa génération paresseuse en combinaison avec la méthode prefix(while:)
pour les séquences, comme décrit dans la proposition d'évolution SE-0045 . Cette dernière appliquée à l'exemple en cours de cette réponse rend l'approche sequence
moins verbeux, incluant clairement les critères de terminaison de la génération d’éléments.
/* for Swift 3.1 */
// ... as above
for f in sequence(first: first, next: { $0 + interval })
.prefix(while: { $0 <= last }) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
Avec Swift 5, vous pouvez choisir l’un des 5 exemples suivants pour résoudre votre problème.
stride(from:to:by:)
fonctionlet first = 0
let last = 10
let interval = 2
let sequence = stride(from: first, to: last, by: interval)
for element in sequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
sequence(first:next:)
fonctionlet first = 0
let last = 10
let interval = 2
let unfoldSequence = sequence(first: first, next: {
$0 + interval < last ? $0 + interval : nil
})
for element in unfoldSequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
AnySequence
init(_:)
initialiseurlet anySequence = AnySequence<Int>({ () -> AnyIterator<Int> in
let first = 0
let last = 10
let interval = 2
var value = first
return AnyIterator<Int> {
defer { value += interval }
return value < last ? value : nil
}
})
for element in anySequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
CountableRange
filter(_:)
let first = 0
let last = 10
let interval = 2
let range = first ..< last
let lazyCollection = range.lazy.filter({ $0 % interval == 0 })
for element in lazyCollection {
print(element)
}
/*
prints:
0
2
4
6
8
*/
CountableRange
flatMap(_:)
let first = 0
let last = 10
let interval = 2
let range = first ..< last
let lazyCollection = range.lazy.compactMap({ $0 % interval == 0 ? $0 : nil })
for element in lazyCollection {
print(element)
}
/*
prints:
0
2
4
6
8
*/
Simplement, code de travail pour Swift 3.0:
let (first, last, interval) = (0, 100, 1)
var n = 0
for _ in stride(from: first, to: last, by: interval) {
n += 1
}