Converting a C-Style for Loop That Uses Division for the Step to Swift 3

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 that
num >= 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



Leave a reply



Submit