How do a i+=2 for-loop in Swift?
Check this
for index in stride(from: 0, to: 5, by: 2){
print(index)
}
Multiple increments in Swift style for loops
Preconditions to answering this: looking over your example
I will assume that you intended to limit i
by i < rawDataOut.count-3
rather than i < rawDataOut.count
, otherwise the rawDataOut[i + 3]
element access by index wouldn't make much sense w.r.t. runtime safety. Anyway, without you showing us rawDataOut
, this is an assumption we shall have to make.
Hence, your original loop (including a verifiable example) looks as follows
/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)
/* your pre-Swift 2.2/3.0 loop */
for var i: Int = 0, j: Int = 0; i < rawDataOut.count-3; i += 4, ++j {
maskPixels[j] = rawDataOut[i + 3]
}
print(maskPixels) //[4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
Using for in ... where
In your specific example case, the multiple increments have a simple relation (j=4*i
) so we could solve this without even making use of an explicit j
iterate, e.g.
/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)
/* your pre-Swift 2.2/3.0 loop */
for i in 0..<(rawDataOut.count-3) where i%4 == 0 {
maskPixels[i/4] = rawDataOut[i + 3]
}
print(maskPixels) // [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
but this is possibly not really of interest for the general discussion of two iterates. We move on to a 2-iterate method combining stride
and enumerate
.
Combining stride
and enumerate
One solution is to enumerate the stride
described by iterate i
in your loop above, and use the enumeration index to construct the second iterate (j
above). In your example, the enumerate
index exactly corresponds to j
, i.e.
/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)
/* Swift >= 2.2 loop */
for (j, i) in 0.stride(to: rawDataOut.count-3, by: 4).enumerate() {
maskPixels[j] = rawDataOut[i + 3]
}
print(maskPixels) // [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
Note that in Swift 3 (as compared to 2.2), it seems as if the default implementations of stride(to:by:)
and stride(through:by:)
to protocol Strideable
(as non-blueprinted extension methods) will be depracated, and that we're back to (as in Swift 1.2) using the global functions stride(from:to:by:)
and stride(from:through:by:)
, see e.g. the current master branch of swift/stdlib/public/core/Stride.swift
Trickier cases: resort to while
For trickier cases, say a signature in your pre-Swift 2.2 loop as
for var i: Int = 0, j: Int = 0; i < rawDataOut.count-3; i += 4, j += i { ... }
you're probably best of simply using a while
loop with one iterate associated with the loop invariant, and a trailing iterate as a free variable; whether this is considered messy or not is a matter of taste, I suppose.
var i = 0, j = 0
while i < rawDataOut.count-3 {
// ...
// increase iterates
i += 4
j += i
}
I assume the reason for removing the C-style loop is that it's, in most cases, directly covered by for in
, stride
etc, and for cases where these don't suffice, a good old' while
, most likely, will.
How to create a for loop with a dynamic increment amount on each iteration in swift now that the C-style loop has been removed
Here's a corrected version using a regular for-in loop over the scaleIntervals
. You also forgot about F# :-)
let scaleIntervals: [Int] = [2,2,1,2,2,2,1]
let notes: [String] = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
func scale(fromNote tonicIndex: Int) -> [String] {
var result: [String] = []
var currentIndex = tonicIndex
for interval in scaleIntervals {
result.append(notes[currentIndex])
currentIndex = (currentIndex + interval) % notes.count
}
return result
}
print(scale(fromNote: 0)) // ["A", "B", "C#", "D", "E", "F#", "G#"]
print(scale(fromNote: 3)) // ["C", "D", "E", "F", "G", "A", "B"]
Just for fun, here's a single-expression version using reduce
. This is really slow to typecheck and probably less efficient, but it's cute:
func scale(fromNote tonicIndex: Int) -> [String] {
return scaleIntervals.reduce((notes: [], index: 0), {
($0.notes + [notes[$0.index]], ($0.index + $1) % notes.count)
}).notes
}
Swift 3: replace c style for-loop with float increment
you can use stride function stride(through:, by:)
for this .. something like
for hue in (minHue).stride(through: maxHue, by: hueIncrement){
// ...
}
From Swift3.0
, you can use stride(from:to:by:)
or stride(from:through:by:)
syntax
for hue in stride(from: minHue, through: maxHue, by: hueIncrement){
//....
}
Swift 2.2 decrementing specific for loop in Swift 3
Your code isn't counting the number of 3-letter words in the array. It is counting the number of 3-letter words at the end of the array. It will return 0
for your sample input array.
When a C-style for loop is very complex, the final fallback solution is to translate it to a while loop. Any C-style for loop can be mechanically converted into an equivalent while loop, which means you can do it even if you don't fully understand what it is doing.
This for loop:
for initialization; condition; increment {
// body
}
is equivalent to:
initialization
while condition {
// body
increment
}
So, your code is equivalent to:
let array = ["hello", "world", nil, "foo", nil, "bar", "Peter Griffin"]
var threeLetterWords = 0
var i = array.count - 1
while i >= 0 && array[i]?.characters.count == 3 {
i -= 1
threeLetterWords += 1
}
print("Found words: \(threeLetterWords)") // says `Found words: 0`
Here is how to use a for loop and guard to do the equivalent of your code:
let array = ["hello", "world", nil, "foo", nil, "bar", "Peter Griffin"]
var num3LetterWords = 0
for word in array.reversed() {
guard word?.characters.count == 3 else { break }
num3LetterWords += 1
}
print(num3LetterWords)
Swift 3 - round-up double of for-loop
Credit to Martin R for this more Swift-y answer:
You can make use of the FloatingPoint protocol, whose behavior is detailed here, to always round up:upperBound.rounded(.up)
Original Answer:
Based on this answer, using ceil(upperBound)
will cause any value greater than (in your example) 12 to be rounded up to 13.
How can I do a Swift for-in loop with a step?
The Swift synonym for a "step" is "stride" - the Strideable protocol in fact, implemented by many common numerical types.
The equivalent of (i = 1; i < max; i+=2)
is:
for i in stride(from: 1, to: max, by: 2) {
// Do something
}
Alternatively, to get the equivalent of i<=max
, use the through
variant:
for i in stride(from: 1, through: max, by: 2) {
// Do something
}
Note that stride
returns a StrideTo
/StrideThrough
, which conforms to Sequence
, so anything you can do with a sequence, you can do with the result of a call to stride
(ie map
, forEach
, filter
, etc). For example:
stride(from: 1, to: max, by: 2).forEach { i in
// Do something
}
Related Topics
Why Are Emoji Characters Like 👩👩👧👦 Treated So Strangely in Swift Strings
How to Unwrap Double Optionals
How to Detect Which Skspritenode Has Been Touched
Does Swift Copy on Write For All Structs
How to Make My Exponentiation Operator Work With All Numeric Types in Swift
Why Do Self and Self Sometimes Refer to Different Types in Static Functions
Nehotspothelper.Register Not Received Call Back Ios11
Xcode 11 & Ios13, Using Uikit Can't Change Background Colour of Uiviewcontroller
How to Display an Activity Indicator With Text on iOS 8 With Swift
What Is a Good Example to Differentiate Between Fileprivate and Private in Swift3
What Is the Cause of This Type Error