Converting a C-style for loop that uses division for the step to Swift 3
MartinR's solution is very generic and useful and should be part of your toolbox.
Another approach is to rephrase what you want: the powers of two from 7 down to 0.
for i in (0...7).reversed().map({ 1 << $0 }) {
print(i)
}
Converting Complex for-loops to Swift 3
In Swift 3 you can use stride(from:to:by:)
for that.
for i in stride(from: r1o.index - 1, to: (r1o.index -1 + (32*r1h)), by: 32){
print(i)
//your code
}
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
}
Express for loops in swift with dynamic range
Using a helper function (originally defined at Converting a C-style for loop that uses division for the step to Swift 3)
public func sequence<T>(first: T, while condition: @escaping (T)-> Bool, next: @escaping (T) -> T) -> UnfoldSequence<T, T> {
let nextState = { (state: inout T) -> T? in
// Return `nil` if condition is no longer satisfied:
guard condition(state) else { return nil }
// Update current value _after_ returning from this call:
defer { state = next(state) }
// Return current value:
return state
}
return sequence(state: first, next: nextState)
}
you can write the loop as
let num = 1000
for i in sequence(first: 5, while: { num/$0 > 0 }, next: { $0 * 5 }) {
print(i)
}
A simpler solution would be a while-loop:
var i = 5
while num/i > 0 {
print(i)
i *= 5
}
but the advantage of the first solution is that the scope of the loop variable is limited to the loop body, and that the loop variable is a constant.
Swift 3.1 will provide a prefix(while:)
method for sequences,
and then the helper function is no longer necessary:
let num = 1000
for i in sequence(first: 5, next: { $0 * 5 }).prefix(while: { num/$0 > 0 }) {
print(i)
}
All of above solutions are "equivalent" to the given C loop.
However, they all can crash if num
is close to Int.max
and $0 * 5
overflows. If that is an issue then you have to check
if $0 * 5
fits in the integer range before doing the multiplication.
Actually that makes the loop simpler – at least if we assume thatnum >= 5
so that the loop is executed at least once:
for i in sequence(first: 5, next: { $0 <= num/5 ? $0 * 5 : nil }) {
print(i)
}
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
}
Can you tell a for-loop to conditionally advance by more than one step?
No, you can't change how a for-in
loop iterates from within the loop.
A while
loop with your own index counter is probably the simplest solution in this case. Though you may be able to make use of sequence(first:next:)
in a for-in
loop.
How to write NSNumber in swift3?
Just for reference the application being built is ann exercise from the excellent book "IOS Programming: The Big Nerd Ranch Guide" chapter 4.
Problem 2 first: "Type 'NumberFormatter.Style' has no member 'DecimalStyle'"
Swift 3 or Xcode 8 have depreciated NSNumberFormatter for NumberFormatter and it makes the code a little easier to read. Your code should work this way
let numberFormatter: NumberFormatter = {
let nf = NumberFormatter()
nf.numberStyle = .decimal
nf.minimumFractionDigits = 0
nf.maximumFractionDigits = 1
return nf
}()
Problem 1: Cannot convert value of type 'Double' to expected argument type 'NSNumber'
Joel Bell has the correct answer. Here is my approach
func updateCelsiuslabel() {
if let value = celsiusValue {
celsiusLabel.text = numberFormatter.string(from: NSNumber(value: value))
}
else {
celsiusLabel.text = "???"
}
}
I hope that helps.
Swift: what is the right way to split up a [String] resulting in a [[String]] with a given subarray size?
I wouldn't call it beautiful, but here's a method using map
:
let numbers = ["1","2","3","4","5","6","7"]
let splitSize = 2
let chunks = numbers.startIndex.stride(to: numbers.count, by: splitSize).map {
numbers[$0 ..< $0.advancedBy(splitSize, limit: numbers.endIndex)]
}
The stride(to:by:)
method gives you the indices for the first element of each chunk, so you can map those indices to a slice of the source array using advancedBy(distance:limit:)
.
A more "functional" approach would simply be to recurse over the array, like so:
func chunkArray<T>(s: [T], splitSize: Int) -> [[T]] {
if countElements(s) <= splitSize {
return [s]
} else {
return [Array<T>(s[0..<splitSize])] + chunkArray(Array<T>(s[splitSize..<s.count]), splitSize)
}
}
Related Topics
How to Find Actual Swiftui API Documentation (And Not Just the Developer Documentation)
Swift, Auto Resize Custom Table View Cells
Nstimer Does Not Invoke a Private Func as Selector
Why am I Allowed Method Access Less Restrictive Than Class Access
Coreplot with Swift: There Is No Yaxis.Majorintervallength
Difference Between Force Unwrapping Optionals and Implicitly Unwrapped Optionals
Get the Last Character of a String Without Using Array
Swift 3.0 Iterate Over String.Index Range
Optional Field Type Doesn't Conform Protocol in Swift 3
"Generic Parameter Could Not Be Inferred" in Swiftui Uiviewrepresentable
Creating a Countableclosedrange<Character>
Swift 4.0 Mapview Running Slow
Read Data Firebase Assign Value