Is there a tidier or better way to write the below nested for...in loops in Swift please? Or is using for...in even the correct way to populate my cards?
for cardNumber in 1...3 {
for cardSymbolIdentifier in 1...3 {
for cardColorIdentifier in 1...3 {
for cardShadingIdentifier in 1...3 {
let card = Card(cardNumber: cardNumber, cardSymbolIdentifier: cardSymbolIdentifier, cardColorIdentifier: cardColorIdentifier, cardShadingIdentifier: cardShadingIdentifier)
deckOfCards.append(card)
}
}
}
}
It definitely does the job, but I can't find anything in the documentation about writing multiple nested loops.
Many thanks in advance,
Andy
There is absolutely nothing wrong with your for loops. They are excellent, well-written Swift. The only problem with your code is that it forces deckOfCards to be mutable (var), which may be undesirable. If it is, you could use a map, but I don't consider this particularly better Swift, just slightly different.
let d = (1...3).flatMap { number in
(1...3).flatMap { symbol in
(1...3).flatMap { color in
(1...3).map { shading in
Card.init(cardNumber: number,
cardSymbolIdentifier: symbol,
cardColorIdentifier: color,
cardShadingIdentifier: shading
)}}}}
I would probably write it this second way, but only for stylistic reasons. Your for loops are absolutely fine.
Note #user28434's comment below. My original version of this had a major bug (it returned the wrong type). I've been writing Swift since the day it was released. I teach Swift. I teach functional programming in Swift. And I screwed it up when writing it on the fly. I would never have made that mistake with a simple for loop. There's a major lesson in there.
If you Do that in a single loop, then it become arithmetically complex
for i in 0..<81 {
deckOfCards.append(
Card(cardNumber: i / 27, cardSymbolIdentifier: i/9 % 3,
cardColorIdentifier: i/3 % 3, cardShadingIdentifier: i % 3)
)
}
or
let deckOfCards = (0..<81).map {
Card(cardNumber: $0 / 27, cardSymbolIdentifier: $0/9 % 3,
cardColorIdentifier: $0/3 % 3, cardShadingIdentifier: $0 % 3)
}
In both example - indexing start with 0, so your class init function should shift indexing little
or
add +1 in every parameter before/after passing
Your code has no optimisation issues at all according to the need but you can make it a little more elegant or swifty (:p)
let values = [1,2,3]
values.forEach { (cardNumber) in
values.forEach { (cardSymbolIdentifier) in
values.forEach { (cardColorIdentifier) in
values.forEach { (cardShadingIdentifier) in
let card = Card(cardNumber: cardNumber, cardSymbolIdentifier: cardSymbolIdentifier, cardColorIdentifier: cardColorIdentifier, cardShadingIdentifier: cardShadingIdentifier)
deckOfCards.append(card)
}
}
}
}
Related
I'm (relatively) new to programming. I was working through Apple's "Introduction to App Development" and since there isn't an answer booklet of some sort I've had to work things out on my own. However there are some things I'm a bit confused about:
There is a problem I'm working on:
This playground has a Chicken type built in to it. A Chicken has a breed and temper property, and both properties are enums.
Here is an array of chickens:
chickens = [{silkie, grumpy}...]
The task is to calculate how many chickens of the breed "leghorn" and temper "hilarious" there are in the array. I've come up with the following code:
var chickenOfInterestCount = 0
for chicken in chickens {
switch chicken.temper {
case .hilarious:
switch chicken.breed {
case .leghorn:
chickenOfInterestCount += 1
default:
chickenOfInterestCount += 0
}
default:
chickenOfInterestCount += 0
}
}
chickenOfInterestCount
It works, but I wonder if there is a more efficient way to do this? Can I make the switch check each chicken for {leghorn, hilarious} and count the number of required chickens directly, rather than using a nested switch? (All of my attempts to try this myself were squashed by scary looking error messages, so I'm guessing no) Following from that, how do for loops work?
When I originally learned for loops, I was under the impression that integers were used to loop through, e.g. the first loop was i = 0, and the code inside performed, then the second loop was i = 1, etc, where "i" could really be anything, and the idea would be the same. Here, "chicken" is used. Why is it that I can set the condition to chicken.temper? What does chicken mean here? Does a for loop respect the type of the array it is looping through? So is what is actually happening here something like "take the 0th Chicken in the array of chickens, call that a 'chicken', then check its temper"?
Well, the first thing I'll mention is that your approach works. As you suspect, it's not the most elegant approach - but you're already instinctively aware of this.
The filter functionality in Swift is powerful and efficient, and Dilan's example will set you in the right direction to begin exploring this. But you'll want to develop a good understanding of control flow on its own - aside from functional programming features like map, reduce, and filter.
For this situation if you're only looking for one combination of breed and temperament, then probably a basic if statement is cleaner than using switch.
var chickenOfInterestCount = 0
for chicken in chickens {
if chicken.breed == .leghorn && chicken.temper == .hilarious {
chickenOfInterestCount += 1
}
}
chickenOfInterestCount
Switch is more useful when you have to do something for each case - it ends up being much cleaner than multiple if / else if statements.
var bantamCount = 0
var leghornCount = 0
var unknownBreedCount = 0
var chillCount = 0
var hilariousCount = 0
var unknownTemperCount = 0
for chicken in chickens {
switch chicken.breed {
case .bantam:
bantamCount += 1
case .leghorn:
leghornCount += 1
default:
unknownBreedCount += 1
}
switch chicken.temper {
case .chill:
chillCount += 1
case .hilarious:
hilariousCount += 1
default:
unknownTemperCount += 1
}
}
Also on your question:
So is what is actually happening here something like "take the 0th Chicken in the array of chickens, call that a 'chicken', then check its temper"?
As Ben pointed out, you're reasoning about this correctly. Within the scope of the loop, there's a var called chicken that is an instance of Chicken (presumably - not sure what you named this Class or Struct) and is a member of the chickens array.
The Swift-y thing to do in these situations is to break out map(), reduce(), compactMap(), and filter()--in your case, filter():
let chickens: [Chicken] = [ silkie, grumpy, dopey, foghorn ]
let hilariousLeghorns = chickens.filter {
$0.breed == .leghorn
&& $0.temper == .hilarious
}
let chickenOfInterestCount = hilariousLeghorns.count
(Thank you for making your example funny!)
In your pseudo-code, your for-loop is a little nest-y, and that can be hard to read. (Mine is probably not much easier--I'd love a code review!) You are in fact declaring a chicken which is going to be assigned the value of each element of chickens in turn. You can do this with any Sequence, like an array, a map, or a set.
To get a old-school for loop, you can loop through a range:
for i in 1...5 {
print(i)
}
This does the same thing: i is assigned the values 1, 2, 3, 4, and 5, in turn, looping 5 times.
Welcome to Programming.This is the model for your scenario .
struct Chicken{
let id:Int
let breed:String
let temper:String
}
enum Breed{
static let leghorn = "leghorn"
static let other = "other"
}
enum Temper{
static let hilarious = "hilarious"
static let other = "other"
}
var chickens:[Chicken] = []
chickens.append(Chicken(id: 1, breed:.leghorn, temper:.hilarious))
chickens.append(Chicken(id: 2, breed:.other, temper:.hilarious))
chickens.append(Chicken(id: 3, breed:.leghorn, temper:.other))
You can get your result from one line with Swift.Use Filter function.This is like for loop and $0 mean current element.It is loop through your array and find elements that satisfy your condition.
print(chickens.filter({$0.breed == .leghorn && $0.temper == .hilarious}).count)
Apple Documentation
Extra info
Task
I am attempting to implement the Gated-GAN architecture using Swift for TensorFlow. In the generator of the Gated-GAN, there are k convolutional blocks (the "Gated-Transformer"), each of which take in a copy of the encoded image. The output of this layer is a single, weighted sum of the outputs of each convolutional block.
In the future, I would like to be able to increase k after a model has already been trained (and, say, fine-tune the k+1th transformer). As such, I don't want to hard-code k into the architecture.
Gated-Transformer diagram (I don't have enough reputation to post the picture directly)
Minimal Working Example
It would be very convenient to write something like this:
struct GatedTransformer: Layer {
// Normally the blocks in the transformer are residual blocks, but
// for simplicity I'll just use Conv2D here.
var convBlocks: [Conv2D<Float>]
/// Custom differentiable input (needed since the layer has two inputs).
struct GatedTransformerInput: Differentiable {
var image: Tensor<Float> // shape=[batch_size, height, width, channel]
var classDistributions: Tensor<Float> // shape=[class_count]
#differentiable
public init(image: Tensor<Float>, classDistributions: Tensor<Float>) {
self.image = image
self.classDistributions = classDistributions
}
}
public init(_ classCount: Int) {
precondition(classCount > 0)
// Some example parameters for Conv2D.
convBlocks = [Conv2D](repeating: Conv2D(filterShape: (3, 3, 128, 128), strides: (1, 1)), count: classCount)
}
var classCount: Int { get { return convBlocks.count } }
#differentiable
func callAsFunction(_ input: GatedTransformerInput) -> Tensor<Float> {
precondition(input.classDistributions.shape.dimensions.last! == self.classCount)
// <problematic_code id=0>
var imageArray: [Tensor<Float>] = [Tensor<Float>](repeating: input.image, count: self.classCount)
for i in 0..<self.classCount {
imageArray[i] = convBlocks[i](input.image).expandingShape(at: 1)
}
let result: Tensor<Float> = Tensor<Float>(concatenating: imageArray, alongAxis: 1)
// </problematic_code>
// Concatenate Tensors, multiply by class distributions, then sum along 'class' axis.
let highRankFactors: Tensor<Float> = input.classDistributions.expandingShape(at: [2, 3, 4])
let broadcastedFactors: Tensor<Float> = highRankFactors.broadcasted(to: result.shape)
return (broadcastedFactors * result).sum(squeezingAxes: 1)
}
}
However, this fails with the compiler error:
cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?
var imageArray: [Tensor<Float>] = [Tensor<Float>](repeating: input.image, count: self.classCount)
^
Alternate Approaches
Build a concatenated Tensor as we go along.
This approach fails because the re-assignment to result is not differentiable. A similar approach could be to use the Tensor += operator, although this does not compile either (Tensor.+= is not implemented as a #differentiable function, according to the official API).
// <problematic_code id=1>
var result: Tensor<Float> = convBlocks[0](input.image).expandingShape(at: 1)
for i in 0..<self.classCount {
let nextResult: Tensor<Float> = convBlocks[i](input.image).expandingShape(at: 1)
result = result.concatenated(with: nextResult, alongAxis: 1)
}
// </problematic_code>
Append to a new Array.
This fails because Array.append is not differentiable.
// <problematic_code id=2>
var imageArray: [Tensor<Float>] = []
for i in 0..<self.classCount {
imageArray.append(convBlocks[i](input.image).expandingShape(at: 1))
}
let result: Tensor<Float> = Tensor<Float>(concatenating: imageArray, alongAxis: 1)
// </problematic_code>
Make GatedTransformerInput a differentiable type.
I'm assuming there is a way to get this to work. However, this would involve conforming GatedTransformerInput to VectorProtocol, which feels like more work than necessary.
Define custom derivative for callAsFunction(...).
This could be another possible approach. However, to compute the derivative, I need to the intermediate array of Tensors. These values are not visible to an outside function, which can only see the input and output of callAsFunction(...)
Summarized Question
Is there a way to leverage Swift's already existing Differentiable types to implement the Gated-Transformer for an arbitrary (and possibly variable) k?
If not, how should I design a new Differentiable type that would allow me to do the above?
Answer
Your minimal working example is very close to doing what you want, and you can fix it with a small adjustment.
The compiler error
cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?
var imageArray: [Tensor<Float>] = [Tensor<Float>](repeating: input.image, count: self.classCount)
^
is happening because the compiler is trying to determine how this use of self.classCount contributes to the gradient. It fails while trying to do this because self.classCount is not differentiable (because it's a non-differentiable integer type).
In this case, you don't actually want uses of self.classCount to contribute to the gradient, so you can make the compiler happy by writing withoutDerivative(at: self).classCount. This tells the compiler to ignore how that particular use of self contributes to the gradient, even though the compiler is differentiating with respect to self.
Alternate Approaches
Some of your alternate approaches can also work.
Concatenated tensor
Use withoutDerivative(at: self).classCount in the for loop bound.
Note 1: The compiler diagnostic for this one could be improved. It's very unclear.
Note 2: I'm not sure why withoutDerivative(at: self).classCount isn't necessary in the for loop bound in the first example.
Using Tensor +=
Tensor += not differentiable because Swift AD currently (as of 2019-11-05) doesn't support differentiating mutating functions like +=. However, you should be able to differentiate functions that use result = result + foo instead of result += foo.
Custom derivative of callAsFunction(_:)
When you define custom derivatives, you specify "VJP" functions that return the original result and a "pullback" closure that calculates the derivative. The "pullback" closure can capture intermediate values from the original result calculation. e.g.
func vjpCallAsFunction(_ input: GatedTransformerInput) -> (Tensor<Float>, ...) {
...
var imageArray = ...
...
func pullback(...) -> ... {
...
<use imageArray>
...
}
return (result, pullback)
}
Of course, this causes unfortunate code duplication between callAsFunction and its VJP. So it's best to use automatically-calculated derivatives when that is possible.
Swift 4.2 introduced a new removeAll {where:} function. From what I have read, it is supposed to be more efficient than using filter {where:}. I have several scenarios in my code like this:
private func getListOfNullDates(list: [MyObject]) -> [MyObject] {
return list.filter{ $0.date == nil }
.sorted { $0.account?.name < $1.account?.name }
}
However, I cannot use removeAll{where:} with a param because it is a constant. So I would need to redefine it like this:
private func getListOfNullDates(list: [MyObject]) -> [MyObject] {
var list = list
list.removeAll { $0.date == nil }
return list.sorted { $0.account?.name < $1.account?.name }
}
Is using the removeAll function still more efficient in this scenario? Or is it better to stick with using the filter function?
Thank you for this question ๐๐ป
I've benchmarked both functions using this code on TIO:
let array = Array(0..<10_000_000)
do {
let start = Date()
let filtering = array.filter { $0 % 2 == 0 }
let end = Date()
print(filtering.count, filtering.last!, end.timeIntervalSince(start))
}
do {
let start = Date()
var removing = array
removing.removeAll { $0 % 2 == 0 }
let end = Date()
print(removing.count, removing.last!, end.timeIntervalSince(start))
}
(To have the removing and filtering identical, the closure passed to removeAll should have been { $0 % 2 != 0 }, but I didn't want to give an advantage to either snippet by using a faster or slower comparison operator.)
And indeed, removeAll(where:) is faster when the probability of removing elements (let's call it Pr)is 50%! Here are the benchmark results :
filter : 94ms
removeAll : 74ms
This is the same case when Pr is less than 50%.
Otherwise, filtering is faster for a higher Pr.
One thing to bear in mind is that in your code list is mutable, and that opens the possibility for accidental modifications.
Personally, I would choose performance over old habits, and in a sense, this use case is more readable since the intention is clearer.
Bonus : Removing in-place
What's meant by removing in-place is the swap the elements in the array in such a way that the elements to be removed are placed after a certain pivot index. The elements to keep are the ones before the pivot element :
var inPlace = array
let p = inPlace.partition { $0 % 2 == 0 }
Bear in mind that partition(by:) doesn't keep the original order.
This approach clocks better than removeAll(where:)
Beware of premature optimization. The efficiency of a method often depends on your specific data and configuration, and unless you're working with a large data set or performing many operations at once, it's not likely to have a significant impact either way. Unless it does, you should favor the more readable and maintainable solution.
As a general rule, just use removeAll when you want to mutate the original array and filter when you don't. If you've identified it as a potential bottleneck in your program, then test it to see if there's a performance difference.
As documented in both Array and Dictionary forEach(_:) Instance methods:
Calls the given closure on each element in the sequence in the same
order as a for-in loop.
Nevertheless, adapted from Sequence Overview:
A sequence is a list of values that you can step through one at a
time. The most common way to iterate over the elements of a sequence
is to use a for-in loop.
Implying that iterating sequence by forEach(_:) or for in:
let closedRange = 1...3
for element in closedRange { print(element) } // 1 2 3
closedRange.forEach { print($0) } // 1 2 3
Or (Array):
let array = [1, 2, 3]
for element in array { print(element) } // 1 2 3
array.forEach { print($0) } // 1 2 3
Would gives the same output.
Why forEach(_:) even exist? i.e what is the benefit of using it instead of the for in loop? would they be the same from performance point view?
As an assumption, it could be a syntactic sugar especially when working with functional programming.
There is no performance benefit offered by forEach. In fact, if you look at the source code, the forEach function actually simply performing for-in. For release builds, the performance overhead of this function over simply using for-in yourself is immaterial, though for debug builds, it results in an observable performance impact.
The main advantage of forEach is realized when you are doing functional programming, you can add it to a chain of functional calls, without having to save the prior result into a separate variable that you'd need if you used for-in syntax. So, instead of:
let objects = array.map { ... }
.filter { ... }
for object in objects {
...
}
You can instead stay within functional programming patterns:
array.map { ... }
.filter { ... }
.forEach { ... }
The result is functional code that is more concise with less syntactic noise.
FWIW, the documentation for Array, Dictionary, and Sequence all remind us of the limitations introduced by forEach, namely:
You cannot use a break or continue statement to exit the current
call of the body closure or skip subsequent calls.
Using the return statement in the body closure will exit only from
the current call to body, not from any outer scope, and won't skip
subsequent calls.
I recently ran across a use case where using forEachwas preferable in a tangible way to for in. Let's say you want to remove all sublayers from a layer. A statement such as the below doesn't work as you need to unwrap the [CALayer]
for layer in self.videoContainerView.layer.sublayers!
If sublayers are nil, you will get a crash. This forces you to check to see if there are sublayers first. However, a forEach makes this much simpler as in the following:
self.videoContainerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
They are more or less interchangeable, but there are two important differences.
break/continue only work in a for .. in
return in forEach will exit the closure, but will not halt the iteration.
The reason for this is that for .. in is a special form in the language (which allows break and continue to work as you expect). It is something that you can't implement in an identical way using the language itself.
However, forEach is not a special form and can be re-implemented identically by writing it as a function.
extension Sequence {
func myOwnForEach(_ body: (Self.Element) throws -> Void) rethrows {
let it = Self.makeIterator()
while let item = it.next() {
body(item)
}
}
}
In addition to above answers one more reason that differentiates for loop from forEach is that with for loop we can also chose to implement that logic using where based pattern matching instead, like
for adBanner in adBanners where !adBanner.isLoading {
The above kind of control flow related features are what makes for loops so powerful, but if we donโt need that level of control, using a call to forEach might give us slightly simpler-looking code.
So in short using a for loop gives us a much greater degree of control over an iteration
When writing a wrapper function to perform an FFT operation in Swift, I arrived at two different ways of passing a Swift array into Accelerate functions that take C array pointers. The first uses .withUnsafePointerToElements():
func fft(var inputArray:[Double]) -> [Double] {
var fftMagnitudes = [Double](count:inputArray.count, repeatedValue:0.0)
inputArray.withUnsafePointerToElements {(inputArrayPointer: UnsafePointer<Double>) -> () in
var zeroArray = [Double](count:inputArray.count, repeatedValue:0.0)
zeroArray.withUnsafePointerToElements { (zeroArrayPointer: UnsafePointer<Double>) -> () in
var splitComplexInput = DSPDoubleSplitComplex(realp: inputArrayPointer, imagp: zeroArrayPointer)
vDSP_fft_zipD(fft_weights, &splitComplexInput, 1, vDSP_Length(log2(CDouble(inputArray.count))), FFTDirection(FFT_FORWARD));
vDSP_zvmagsD(&splitComplexInput, 1, &fftMagnitudes, 1, vDSP_Length(inputArray.count));
}
}
return sqrt(fftMagnitudes)
}
and the second merely passes the Swift arrays in using &:
func fft(var inputArray:[Double]) -> [Double] {
var fftMagnitudes = [Double](count:inputArray.count, repeatedValue:0.0)
var zeroArray = [Double](count:inputArray.count, repeatedValue:0.0)
var splitComplexInput = DSPDoubleSplitComplex(realp: &inputArray, imagp: &zeroArray)
vDSP_fft_zipD(fft_weights, &splitComplexInput, 1, vDSP_Length(log2(CDouble(inputArray.count))), FFTDirection(FFT_FORWARD));
vDSP_zvmagsD(&splitComplexInput, 1, &fftMagnitudes, 1, vDSP_Length(inputArray.count));
return sqrt(fftMagnitudes)
}
Both appear to operate in the same manner, with the latter being cleaner and shorter. However, I'm not sure if the second way of doing this opens me up to the local inputArray copy and the zeroArray array being deallocated via ARC after their last usage (like what happens here), leaving a dangling pointer to an array that no longer exists.
It seems that .withUnsafePointerToElements() has to serve some purpose, but I can't quite figure out what it is. Is it required to guarantee the lifetime of the backing arrays in the above, or am I safe simply using & to pass these arrays into C functions?
I believe you do need to extend the lifetimes. I originally wrote my FFT code like your second example, but I've grown to believe this is unsafe. The problem is that the docs only seem to promise that a & reference will protect you from destruction until the end of the function call. So zeroArray in this case would be protected until the end of the DSPDoubleSplitComplex line. Since DSPDoubleSplitComplex just holds UnsafePointer, I don't see any reason to believe that can extend the life of zeroArray. (I assume the same applies to inputArray.)
I'm doing it a little differently that I think reads a little better:
// Generate a split complex vector from the real data
var realp = [Double](count:Int(fftLength), repeatedValue:0.0)
var imagp = realp
withExtendedLifetime(realp) { () -> () in
withExtendedLifetime(imagp) {
var splitComplex = DSPDoubleSplitComplex(realp:&realp, imagp:&imagp)
ctozD(ConstUnsafePointer(signal), 2, &splitComplex, 1, fftLength)
// Take the fft
fft_zripD(fftsetup, &splitComplex, 1, log2N, FFTDirection(kFFTDirection_Forward))
... rest of fft
}
}
I'm avoiding the extra pointer variable by using withExtendedLiftetime. I then can just use &realp and &imagp directly. The one required () -> () in can be eliminated this way if you like:
func withExtendedLifetime<T>(x: T, f: () -> () ) {
return Swift.withExtendedLifetime(x, f)
}
...
withExtendedLifetime(realp) {
withExtendedLifetime(imagp) {
var splitComplex = DSPDoubleSplitComplex(realp:&realp, imagp:&imagp)
ctozD(ConstUnsafePointer(signal), 2, &splitComplex, 1, fftLength)
...
Totally off-topic, but I notice you pass the real component in directly without calling ctozD. I thought Data Packing for Real FFTs indicates that you need to reorganize before calling fft_*. Your math is generally better than mine, so I may be missing something here. My full version is https://gist.github.com/rnapier/399676bd389c270e7b66